#!/usr/bin/perl
use lib '/home/thestrangers/erealms/ethereal/mgmt/perl';
################################################################################
# Created : Martin Foster
# Modified : 01-Jan-2007
################################################################################
#
# Gallery View - Script part of Ethereal Realms, designed to display and list
# galleries and associated works
# Copyright (C) 2000-2007 Martin Foster
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Author of this script can be contacted at the following:
# E-Mail : martin@ethereal-realms.org
# Address : 4-3526 Wolfe Cres
# Halifax, Nova Soctia
# B3L 3S2
#
#################################################################################
use CGI qw(-no_debug -nosticky); # Common gateway interface
use CGI::Carp qw(fatalsToBrowser); # CGI Error logs
use Number::Format qw(:subs); # Number formatting library
use strict; # Strict variable enforcement
use Ethereal::Database; # Database handler
use Ethereal::Filter; # Filter handling
use Ethereal::Login; # Login functionality
use Ethereal::Mail; # Mail handler
use Ethereal::Menu; # Consistent menu
use Ethereal::Option; # Option handler
use Ethereal::Param; # Parameter control
use Ethereal::Template; # Template handler
use Ethereal::Words; # Word processing and stemming
#################################################################################
# Gobal override
#################################################################################
$CGI::POST_MAX=1024 * 50; # Maximum posts
$CGI::DISABLE_UPLOADS = 1; # Disable uploads
################################################################################
# Data Members
################################################################################
my $cgi; # Common gateway interface handle
my $database; # Database handle
my $login; # Login handle
my $menu; # Menu handle
my $param; # Parameter hash
my $tmpl; # Template handle
my $ready = 'False'; # Ready for processing
my $sparam; # Scripted parameter string
my @pass; # Passage of variables
my %gal; # Gallery hash
my %sparam; # Scripted parameters
################################################################################
# Program Area
################################################################################
# Initial handles
$cgi = new CGI;
$database = new Ethereal::Database();
# Connect and fetch
$database->Connect($cgi);
# Kill switch
exit if $database->{'COMP_GALLERY'} eq 'false';
# Set title
$database->{'TITLE'} = $database->{'SYS'}{'TitGallery'};
# Parameter handling
$param = new Ethereal::Param($database, $cgi);
$param->GetParam();
# Link with hash
$database->GetHashGallery(\%gal);
# Create instances
$tmpl = new Ethereal::Template(\%gal);
$menu = new Ethereal::Menu($database, $param);
$login = new Ethereal::Login($database, $cgi, $param, $menu, \%gal);
# Enable custom header and footer
$login->{'HEADER'} = $database->DocumentGetGalleryHeader();
$login->{'FOOTER'} = $database->DocumentGetGalleryFooter();
# Fetch and format
$sparam = $cgi->path_info();
$sparam =~ s/^(\/)(.*)(\/)?$/$2\//;
# Differs based on what is pulled
if ($sparam =~ /^(image|text)/i)
{
# This requires a tree-like depth in order to move freely
# between galleries and genres.
($sparam{'TYP'},
$sparam{'SUB'},
$sparam{'GRE'},
$sparam{'GAL'},
$sparam{'LYR'},
$sparam{'WRK'},
$sparam{'POS'}) = split(/\//, $cgi->unescape($sparam));
}
else
{
# This is more direct, works have no need for that depth
# as they are viewed indepepdantly.
($sparam{'ACT'},
$sparam{'GAL'},
$sparam{'LYR'},
$sparam{'WRK'},
$sparam{'ADD'}) = split(/\//, $cgi->unescape($sparam));
}
# Possible authentication methods
# Determine state of readiness
if (defined($param->{'USER'}))
{
# Authenticate
# Assign if true
$ready = 'True'
if ($login->GetVerificationNormal());
}
else
{
# Require a header
print $cgi->header();
# Change state
$ready = 'True';
}
# Bypass if necessary
if ($ready eq 'True')
{
# Disable certain features
# Disable independance and header generation
$login->{'AUTOMATE'} = 0;
$login->{'NODEPEND'} = 0;
# Page header
HeaderRewrite($database, $cgi, $tmpl, $menu, \%sparam, \%gal);
# Generate cleaner parameter list
push(@pass, $database, $login, $cgi, $param, $tmpl, \%sparam, \%gal);
# Gallery's root definition
# Root defined
if ((defined($sparam{'GRE'}))
&& (length($sparam{'GRE'}) > 3))
{
# Work details
# Shows works allowing linear movement
if ((defined($sparam{'GAL'}))
&& (defined($sparam{'WRK'}))
&& ($sparam{'GAL'} =~ /^\d+$/)
&& ($sparam{'WRK'} =~ /^\d+$/))
{
# Work specific display
WorkDetail(@pass);
}
# Work listing
# Lists all works within gallery
elsif ((defined($sparam{'GAL'}))
&& ($sparam{'GAL'} =~ /^\d+$/))
{
# Work list
WorkList(@pass);
}
# Final step of the puzzle
else
{
# List galleries
GalleryList(@pass);
}
}
# Searching capability
# Work search
elsif ((defined($sparam{'ACT'}))
&& ($sparam{'ACT'} eq 'search'))
{
# Simply one window
WorkSearch(@pass);
}
# Commenting ability
# Comment viewer
elsif ((defined($sparam{'ACT'}))
&& ($sparam{'ACT'} eq 'comment'))
{
# Basic check
if ((defined($sparam{'GAL'}))
&& (defined($sparam{'WRK'})))
{
# Verify for operation
# Removal of comment
if ((defined($sparam{'ADD'}))
&& ($sparam{'ADD'} =~ /^\d+$/))
{
# Remove comment
CommentRemove(@pass);
}
# Creation of a new comment
elsif ((defined($sparam{'ADD'}))
&& ($sparam{'ADD'} eq 'new'))
{
# Remove comment
# Create comments
CommentWrite(@pass);
}
# Simply display
else
{
# Display comments
# Directly display to screen
print CommentDisplay(@pass);
}
}
}
# Default behaviour
# Show member which genres are available
else
{
# Select the genre TYP and SUB-type
GenreList(@pass);
}
# Document footer
print $database->DocumentGetGalleryFooter(), "\n";
}
################################################################################
# Sub-Routines
################################################################################
#####################
# Check Authorization
#
# In certain causes, realms will choose to carry an adult rating. In such a
# case, there is a need to prevent people from using the system when such
# a circumstance takes place.
sub CheckAuth
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $param = shift; # Paramater handler
my $sparam = shift; # Parameter line hash
my $tmpl = shift; # Template handle
my $gal = shift; # Gallery hash
my $choice = shift; # Choice of the matter
my $rating; # Rating to realm
#####################
# Program area
# Retreive information
($rating) = $database->DataGet("SELECT GalleryRating
FROM Gallery
WHERE GalleryID=?",
$sparam->{'GAL'}
);
# Reasons to check
if ((defined($param->{'USER'}))
|| ($rating eq $gal->{'SetRestricted'})
|| (defined($choice)))
{
# Authenthicate
if ($login->GetVerificationNormal())
{
# More checks
if ($rating eq $gal->{'SetRestricted'})
{
# Invalid
if ($database->{'USR'}{'Verified'} eq 'no')
{
# Display error
$tmpl->Show('TmplMsg',
MMESSAGE => $gal->{'MsgRestricted'}
);
# False
return 0;
}
}
# Return true
return 1;
}
# Return false
return 0;
}
# Always return true
return 1;
}
#####################
# Comment Display
#
# If one has the capability of composing messages, then one will also need to
# be able to view them. This is a general, all purpose method that allows
# for attached and semi-independant use.
sub CommentDisplay
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $limit = shift; # Retreival limit
my $res; # Results
my $rsth; # Query handle
my $comment; # Comment settings
my $name; # Name of work
my $access; # Username
my $gummy; # Gummy name
my $rate; # Rating
my $vote; # Votes
my $ibio; # Biographical line
my $idelete; # Delete link
my $inline; # Inline parameters
my $url; # Self referencing link
my $listing; # Comments listing
my $nav; # Navigational business
my $return; # Returned template
my $votes; # Votes generated
#####################
# Program Area
# Initialize
$return = '';
# Make sure values are sane
if (($sparam->{'WRK'} =~ /^\d+$/)
&& ($sparam->{'GAL'} =~ /^\d+$/))
{
# Things are in order
($name) = $database->DataGetWorkName($sparam->{'WRK'}, $sparam->{'GAL'});
# Continue as planned
if (defined($name))
{
# Force authenthication reguardless
return 0 unless (CheckAuth($database, $login, $param, $sparam, $tmpl, $gal));
# Retreive values
($comment) = $database->DataGetGalleryComment($sparam->{'GAL'});
($access) = $database->DataGetGalleryJanitor($sparam->{'GAL'}, $param->{'USER'})
if (defined($param->{'USER'}));
# Initialize elements
$nav = '';
$listing = '';
$votes = '';
# Only display if needed
# Comments
if (($comment eq 'comment')
|| ($comment eq 'combo'))
{
# Determine limit
$limit = (defined($limit)) ? "LIMIT $limit" : "";
# Prepare query
# Set handle if need be
$database->Pull(\$rsth, "SELECT
c.CommentID AS \"CommentID\",
c.PuppetName AS \"PuppetName\",
p.PuppetShort AS \"PuppetShort\",
p.PuppetGummy AS \"PuppetGummy\",
c.PuppeteerLogin AS \"PuppeteerLogin\",
c.CommentPost AS \"CommentPost\",
getDate(c.CommentTimestamp) AS \"CommentTimestamp\"
FROM Comment c
INNER JOIN Puppet p
ON (c.PuppetName=p.PuppetName AND PuppetPool='system')
WHERE WorkID=?
AND GalleryID=?
AND CommentPost IS NOT NULL
ORDER BY CommentTimestamp DESC $limit",
$sparam->{'WRK'},
$sparam->{'GAL'}
);
# Self referencing links
$url = $database->{'SYS'}{'LnkIntGallery'} . '/comment/'
. $sparam->{'GAL'} . '/'
. $sparam->{'LYR'} . '/'
. $sparam->{'WRK'};
# Inline parameters general
$inline = (defined($param->{'USER'}))
? $param->EmbedInline(USER=>$param->{'USER'}, CRYPT=>$param->{'CRYPT'})
: '';
# Necessary fetching
# Initial acid test
if ($res = $rsth->fetchrow_hashref())
{
# Initialize
$idelete = '';
# Loop and retrieve
do
{
# Biographical link
$ibio = '/' . $res->{'PuppetShort'} . '/system' . $inline;
# Deletion handle
$idelete = $tmpl->Pass('TagDelete',
MLINK => $url . '/' . $res->{'CommentID'} . $inline
) if ((defined($param->{'USER'}))
&& (defined($access)));
# Check gummy
$gummy = (defined($res->{'PuppetGummy'}))
? $res->{'PuppetGummy'}
: $gal->{'TagGummyDef'};
# Subsequent rows
$listing .= $tmpl->Pass('TmplCommentList',
MCOMMENT => $res->{'CommentPost'},
MDATE => $res->{'CommentTimestamp'},
MDELE => $idelete,
MPUPPET => $res->{'PuppetName'},
MGUMMY => $gummy,
MLINK => $database->{'SYS'}{'LnkIntBio'} . $ibio
);
} while ($res = $rsth->fetchrow_hashref());
}
# Finish
$rsth->finish();
# Navigational propreties
# Complete listing
$nav .= $tmpl->Pass('TagNavTarget',
MNAME => $gal->{'TagNavComplete'},
MLINK => $url. $inline,
MTARGET => 'COMMENT_' . $sparam->{'GAL'} . 'x' . $sparam->{'WRK'}
) if ($limit =~ /^LIMIT/);
# Write to comment
$nav .= $tmpl->Pass('TagNavTarget',
MNAME => $gal->{'TagNavComment'},
MLINK => $url . '/new' . $inline,
MTARGET => 'COMMENT_' . $sparam->{'GAL'} . 'x' . $sparam->{'WRK'}
) if ($sparam->{'WRK'} != 1);
}
# Rating
if (($comment eq 'rating')
|| ($comment eq 'combo'))
{
# Retrieve values
($rate, $vote) = $database->DataGetWorkAvg($sparam->{'GAL'}, $sparam->{'WRK'});
# Display
$votes .= $tmpl->Pass('TmplVotes',
MITENAME => $name,
MOLVOTES => $vote,
MRATINGS => $rate
);
}
# Generate final template
$return = $tmpl->Pass('TmplComment',
MNAME => $name,
MCOMMENT => $listing,
MNAV => $nav,
MVOTES => $votes
);
}
}
# Return comments
return $return;
}
#####################
# Comment Remove
#
# In order to cope with double posts, annoying messages or things that the artists
# simply cannot agree upon, the comments can be managed by owner.
sub CommentRemove
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $comment; # Comment settings
my $access; # Access privs
#####################
# Program Area
# Force authenthication reguardless
return 0 unless (CheckAuth($database, $login, $param, $sparam, $tmpl, $gal, 'true'));
# Retreive values
($comment) = $database->DataGetGalleryComment($sparam->{'GAL'});
($access) = $database->DataGetGalleryJanitor($sparam->{'GAL'}, $param->{'USER'})
if (defined($param->{'USER'}));
# Only display if needed
if (($comment eq 'comment')
|| ($comment eq 'combo'))
{
# User matches
if (defined($access))
{
# Remove entry
$database->Quick("DELETE FROM Comment
WHERE CommentID=?
AND WorkID=?
AND GalleryID=?",
$sparam->{'ADD'},
$sparam->{'WRK'},
$sparam->{'GAL'}
);
}
}
# Standard entrance
print CommentDisplay($database, $login, $cgi, $param, $tmpl, $sparam, $gal);
}
#####################
# Comment Write
#
# Part of the system, as to allow for rating and commenting of works themselves.
sub CommentWrite
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $filter; # Filter handler
my $send; # Mail sender
my $table; # Table handler
my $comment; # Comment settings
my $name; # Name of work
my $puppet; # Puppet default
my $mail; # Mail comment
my $post; # Post
my $rate; # Rating
my $wcomment; # Commenting field
my $wpuppet; # Puppet popup
my $wrating; # Puppet popup
my $wsubmit; # Post submit
my @puppet; # List of puppets
my @rating = qw(1 2 3 4 5 6 7 8 9 10); # Rating scale
#####################
# Program Area
# Things are in order
($name) = $database->DataGetWorkName($sparam->{'WRK'}, $sparam->{'GAL'});
# Continue as planned
if (defined($name))
{
# Force authenthication reguardless
return 0 unless (CheckAuth($database, $login, $param, $sparam, $tmpl, $gal, 'true'));
# Retreive gallery comment
($comment) = $database->DataGetGalleryComment($sparam->{'GAL'});
# Proceed with comment generation
if ($comment ne 'none')
{
# Write post
if (defined($param->{'CPUPPET'}))
{
# Evaluate change
eval
{
# Post handling
if (($comment eq 'comment')
|| ($comment eq 'combo'))
{
# Create instance
$filter = new Ethereal::Filter();
# Safety
$post = $filter->StripHTML($param->{'CPOST'});
$mail = $post;
# Verify
if (length($post) > 3)
{
# Post handling
$post =~ s/$/\n/;
# Truncate Length
$post = substr(DBI::neat($post, 1026), 1, -1);
# Hyperlinks
$post =~ s/(http:\/\/.*?)(\s|$)/$gal->{TagHyperlink}<\/A> /gm;
$post =~ s/([\w\.\-]*?\@[\w\.\-]*?\..*?)(\s|$)/$gal->{TagEmail}<\/A> /gm;
# Human readability
$post =~ s/\n/
/gs;
}
else
{
# Undefine as to not see
$post = undef;
}
}
# Basic ranting handling
$rate = ((defined($param->{'CRATING'})) && ($param->{'CRATING'} =~ /^\d+$/))
? $param->{'CRATING'}
: 0;
# Insert row
$database->Write("INSERT INTO Comment
(WorkID,
GalleryID,
PuppetName,
PuppeteerLogin,
CommentPost,
CommentRating)
VALUES(?,?,?,?,?,?)",
$sparam->{'WRK'},
$sparam->{'GAL'},
$param->{'CPUPPET'},
$param->{'USER'},
$post,
$rate);
# Rating update
if (($comment eq 'rate')
|| ($comment eq 'combo'))
{
# Calculate average
($rate) = $database->DataGetWorkAvg($sparam->{'GAL'}, $sparam->{'WRK'});
# Update
$database->Write("UPDATE Work
SET WorkRating=?
WHERE WorkID=?
AND GalleryID=?",
$rate,
$sparam->{'WRK'},
$sparam->{'GAL'});
}
# Commit
$database->Commit();
};
# If block failed
if ($@)
{
# Issue warning
warn("Transaction aborted: $@");
# Undo incomplete changes
$database->Rollback();
}
else
{
# Mail notification to user
if ((defined($mail))
&& (length($mail) > 3))
{
# Postage handling
# Retreive notice message and contact
my ($notice) = $database->DocumentGetGalleryNotice();
my ($user) = $database->DataGetGalleryOwner($sparam->{'GAL'});
# Full contact
my ($email) = $database->DataGetPuppeteerEmail($user);
my ($fname) = $database->DataGetPuppeteerName($user);
# Create instance
$send = tie(*MAIL, 'Ethereal::Mail', $database);
# Initial setup
$send->SetSubject($database->{'SYS'}{'SetGalleryPrefix'} . $name);
# Search and replace
$send->SetSearch(
MDATE => $database->DataGetDate(),
MFROM => $param->{'CPUPPET'},
MMESG => $mail,
MMAIL => "$database->{SYS}{SetInfoContactName}\n$database->{SYS}{SetInfoContactAddress}",
MWORK => $name
);
# Recipients
$send->AddTo("$fname <$email>");
# Add message
print MAIL $notice;
# Close and send
close(MAIL);
}
# Normal works
# Simply display here and now
print CommentDisplay($database, $login, $cgi, $param, $tmpl, $sparam, $gal);
}
}
# Display form
# Necessary for people to post comments
else
{
# Puppet names
$database->GetListPuppetYours(\@puppet, $param->{'USER'});
# Puppet default
($puppet) = $database->DataGetDefault($param->{'USER'});
# Append abstaining
unshift(@rating, $gal->{'TxtAbstain'});
# Generate widget
$wpuppet = (defined($database->{'DEFAULT'}))
? $cgi->hidden('CPUPPET', $database->{'DEFAULT'})
: $cgi->popup_menu('CPUPPET', \@puppet, $puppet);
$wrating = $cgi->popup_menu('CRATING', \@rating, $rating[0]);
# Submit button
$wsubmit = ($comment eq 'rating')
? $gal->{'TxtRate'}
: $gal->{'TxtPost'};
# Display information
# Form
print $cgi->start_form();
print $param->EmbedNormal($param->Flat());
# Rating indicator
$wrating = (($comment eq 'rating') || ($comment eq 'combo'))
? $tmpl->Pass('TmplWriterRate', WRATING=>$wrating)
: '';
# Comments
$wcomment = (($comment eq 'comment') || ($comment eq 'combo'))
? $tmpl->Pass('TmplWriterComment',
WCOMMENT => $cgi->textarea(
-name => 'CPOST',
-rows => 3,
-columns => 75,
-wrap => 'SOFT'
)
)
: '';
# Display completed template
$tmpl->Show('TmplWriter',
MRATE => $wrating,
MCOMMENT => $wcomment,
WPUPPET => $wpuppet,
WSUBMIT => $cgi->submit($wsubmit)
);
# Form
print $cgi->end_form(), "\n";
}
}
# Warn author has disabled comments
else
{
# Warn users comments are disabled
$tmpl->Show('TmplMsg', MMESSAGE=>$gal->{'MsgComment'});
}
}
# Invalid entry
else
{
# Warn that things are off
$tmpl->Show('TmplMsg', MMESSAGE=>$gal{'MsgParam'});
}
}
#####################
# Gallery List
#
# Provides the front end to the gallery system itself. Will allow the user
# to select from a list of galleries and move on from there.
sub GalleryList
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $statement; # Query statement
my $res; # Query results
my $descr; # Description field
my $highlight; # Highlighted image
my $list; # List of galleries
my $newness; # Newness factor
my $page; # Nav page
my $url; # Self-referencing url
my $link; # Generated link
my $inline; # Standard inline
my $genre; # Gallery genre
my $pos; # Positional handling
my $sub; # Gallery sub type
my $type; # Gallery type
my $sort; # Sort order
my $osort; # Original sort order
my $offset; # Starting position
my $total; # Amount of entries
#####################
# Program area
# Capture self-referencing link
$url = $database->{'SYS'}{'LnkIntGallery'};
# Sorting method
# Determine sort
$sort = (defined($sparam->{'ACT'}))
? $sparam->{'ACT'}
: 'name';
$osort = $sort;
# Translate to query
if ($sort eq 'date') { $sort = 'GalleryUpdated DESC'; }
elsif ($sort eq 'rating') { $sort = 'GalleryRating ASC, GalleryName ASC'; }
else { $sort = '"GalleryNewness" DESC, GalleryName ASC' }
# Quickly grab total entries
($total) = $database->DataGet("SELECT COUNT(*)
FROM Exhibition
WHERE GalleryType=?
AND GallerySub=?
AND GalleryGenre=?",
$sparam->{'TYP'},
$sparam->{'SUB'},
$sparam->{'GRE'}
);
# Position based handling
# Adjusting
$pos = $sparam->{'GAL'};
# Determine position
$pos = ((defined($pos)) && ($pos =~ /^\d+$/))
? $pos
: 1;
# Determine offset
$offset = ($pos - 1) * $gal->{'SetRetrieve'};
# Information display
# Main display
$database->Pull(\$statement, "SELECT
GalleryID AS \"GalleryID\",
PuppeteerLogin AS \"PuppeteerLogin\",
GalleryName AS \"GalleryName\",
GalleryRating AS \"GalleryRating\",
GalleryDescription AS \"GalleryDescription\",
GalleryThumbnail AS \"GalleryThumbnail\",
getDate(GalleryCreated) AS \"GalleryCreated\",
getDate(GalleryUpdated) AS \"GalleryUpdated\",
getNew(GalleryUpdated) AS \"GalleryNewness\",
WorkCount AS \"WorkCount\"
FROM Exhibition
WHERE GalleryType=?
AND GallerySub=?
AND GalleryGenre=?
ORDER BY $sort LIMIT $gal->{SetRetrieve} OFFSET $offset",
$sparam->{'TYP'},
$sparam->{'SUB'},
$sparam->{'GRE'}
);
# Quick verification
if ($res = $statement->fetchrow_hashref())
{
# Navigational menu
$type = $cgi->escape($sparam->{'TYP'});
$sub = $cgi->escape($sparam->{'SUB'});
$genre = $cgi->escape($sparam->{'GRE'});
# Self referencing link
$link = $url . '/' . $type . '/'
. $sub . '/' . $genre . '/'
. $osort;
# Inline parameter enbed
$inline = (defined($param->{'USER'}))
? $param->EmbedInline($param->Flat())
: '';
# Capture nav line
$page = Navigation($tmpl, $gal, $gal->{'SetRetrieve'}, $total, $pos, $link, $inline);
# Initialize
$list = '';
# Continue
do
{
# Determine highlighting
$highlight = (($sparam->{'TYP'} =~ /image/i) && (defined($res->{'GalleryThumbnail'})))
? $tmpl->Pass('TmplGalleryHighlight', LTHUMB => $res->{'GalleryThumbnail'})
: '';
# Newness calculation
$newness = ($res->{'GalleryNewness'} != 0)
? $gal->{'TagNewness'}
: '';
# Link creation
$link = $url . '/' . $type . '/'
. $sub . '/' . $genre . '/'
. $res->{'GalleryID'};
# Description
$descr = (defined($res->{'GalleryDescription'}))
? $res->{'GalleryDescription'}
: $gal->{'TxtDescription'};
# Display information
$list .= $tmpl->Pass('TmplGalleryList',
MAUTHOR => PenNames($database, $param, $tmpl, $gal, $res->{'GalleryID'}, $inline),
MCREATED => $res->{'GalleryCreated'},
MDESCR => $descr,
MHLIGHT => $highlight,
MLINK => $link . $inline,
MNAME => $res->{'GalleryName'},
MCOUNT => $res->{'WorkCount'},
MRATING => $res->{'GalleryRating'},
MUPDATED => $res->{'GalleryUpdated'},
MNEWNESS => $newness
);
} while ($res = $statement->fetchrow_hashref());
# Self referencing link
$link = $url . '/' . $type . '/'
. $sub . '/' . $genre;
# Display template
$tmpl->Show('TmplGallery',
LSTGAL => $list,
LSTNAV => $page,
LSTSORT => $sort,
MSUB => $sparam->{'SUB'},
MGENRE => $sparam->{'GRE'},
LTYPE => $url . $inline,
LSUB => $url . '/' . $type . '/' . $sub . $inline,
LGENRE => $url . '/' . $type . '/' . $sub . '/' . $genre . $inline,
LSDATE => $link . '/date' . $inline,
LSRATE => $link . '/rate' . $inline,
LSNAME => $link . '/name' . $inline,
LSEARCH => $url . '/search' . $inline
);
}
# Nothing to see
# Move along
else
{
# Display error message
$tmpl->Show('TmplSrch', MMESSAGE=>$gal->{'MsgListing'});
}
# End statement
$statement->finish();
}
#####################
# Genre List
#
# Exists to provide a fuller front-end to the galleries. Which would allow for
# spidering and even a nicer interface for people to use when wanting to see what
# is available.
sub GenreList
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $statement; # Query handle
my $cres; # Count results
my $dres; # Description results list
my $gres; # Genres results list
my $tres; # Types results list
my $count; # Occurences of type
my $description; # Description
my $inline; # Inline parameter set
my $link; # Temporary constructed url
my $url; # Self referencing link
my %descr; # Description hash
my %num; # Number of entries reached
#####################
# Program Area
# Self-referencing link
$url = $database->{'SYS'}{'LnkIntGallery'};
# Inline parameter enbed
$inline = (defined($param->{'USER'}))
? $param->EmbedInline($param->Flat())
: '';
# Type definition
# Users have selected a type
if ((defined($sparam->{'TYP'}))
&& (defined($sparam->{'SUB'})))
{
# Descriptions handling
# Decriptions are not native to exhibition table
$database->Pull(\$statement, "SELECT
GenreName AS \"Genre\",
GenreDescription AS \"Description\"
FROM Genre
WHERE GenreType ILIKE ?
AND GenreSub ILIKE ?",
$sparam->{'TYP'},
$sparam->{'SUB'}
);
# Loop and place in a hash
while ($dres = $statement->fetchrow_hashref())
{
# Creation of hash
$descr{$dres->{'Genre'}} = $dres->{'Description'};
}
# End query
$statement->finish();
# Main display
# Initialize
my $list = '';
# Retreive sections list
# Prepare and execute
$database->Pull(\$statement, "SELECT
GalleryGenre AS \"Genre\",
COUNT(*) AS \"Count\"
FROM Exhibition
WHERE GalleryType ILIKE ?
AND GallerySub ILIKE ?
GROUP BY GalleryGenre
ORDER BY GalleryGenre",
$sparam->{'TYP'},
$sparam->{'SUB'}
);
# Display all available genres
# Loop and display
while ($gres = $statement->fetchrow_hashref())
{
# Generate link
$link = $url . '/'
. $sparam->{'TYP'} . '/'
. $cgi->escape($sparam->{'SUB'}) . '/'
. $cgi->escape($gres->{'Genre'});
# Description
$description = (defined($descr{$gres->{'Genre'}}))
? $descr{$gres->{'Genre'}}
: $gal->{'TxtDescription'};
# Append output
$list .= $tmpl->Pass('TmplGenreDescription',
MCOUNT => $gres->{'Count'},
MDESCR => $description,
MGENRE => $gres->{'Genre'},
LGENRE => $link . $inline
);
}
# Finish up
$statement->finish();
# Generate link
$link = $url . '/'
. $sparam->{'TYP'} . '/'
. $cgi->escape($sparam->{'SUB'});
# Display wrapper template
$tmpl->Show('TmplGenreSub',
LSTSUB => $list,
MSUB => $sparam->{'SUB'},
LSUB => $link . $inline,
LTYPE => $url,
LSEARCH => $url . '/search'
);
}
# No major-type selected
# Mostly users coming in from cold
else
{
# Get a count for every subtype
$database->Pull(\$statement, "SELECT
GalleryType AS \"Type\",
GallerySub AS \"Sub\",
COUNT(*) AS \"Count\"
FROM Exhibition
GROUP BY GalleryType, GallerySub");
# Populate hash
while ($cres = $statement->fetchrow_hashref())
{
# Put in the number
$num{"$cres->{Type}.$cres->{Sub}"} = $cres->{'Count'};
}
# Finish query
$statement->finish();
# Main display
# Initialize
my $img = '';
my $txt = '';
# Define
my $count = 0;
# Retreive sections list
# Prepare and execute
$database->Pull(\$statement, "SELECT
GenreType AS \"Type\",
GenreName AS \"Sub\",
GenreDescription AS \"Description\"
FROM Genre
WHERE GenreType IN ('image','text')
AND GenreSub=''
GROUP BY GenreType, GenreName, GenreDescription
ORDER BY GenreName",
);
# Display all available genres
# Loop and display
while ($tres = $statement->fetchrow_hashref())
{
# Define count
$count = (defined($num{"$tres->{Type}.$tres->{Sub}"}))
? $num{"$tres->{Type}.$tres->{Sub}"}
: 0;
# Skip if necessary
next if ($count == 0);
# Generate link
$link = $url . '/'
. $tres->{'Type'} . '/'
. $cgi->escape($tres->{'Sub'});
# Description
$description = (defined($tres->{'Description'}))
? $tres->{'Description'}
: $gal->{'TxtDescription'};
# Append output
# Reason why grouping was not necessary
if ($tres->{'Type'} eq 'image')
{
# Append to image list
$img .= $tmpl->Pass('TmplGenreDescription',
MCOUNT => $count,
MDESCR => $description,
MGENRE => $tres->{'Sub'},
LGENRE => $link . $inline
);
}
else
{
# Append to text list
$txt .= $tmpl->Pass('TmplGenreDescription',
MCOUNT => $count,
MDESCR => $description,
MGENRE => $tres->{'Sub'},
LGENRE => $link . $inline
);
}
}
# Finish up
$statement->finish();
# Display wrapper template
$tmpl->Show('TmplGenreType',
LSTIMAGE => $img,
LSTTEXT => $txt,
LSEARCH => $url . '/search'
);
}
# Return
return 1;
}
#####################
# Header rewrite
#
# Used to rewrite the HTML header as to properly list the Authors name
# and gallery name in the title field.
sub HeaderRewrite
{
#####################
# Data members
my $database = shift; # Database handler
my $cgi = shift; # Common gateway interface
my $tmpl = shift; # Template handler
my $menu = shift; # Menu rewrite
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery parameter
my $link; # Link name
my $tree; # Tree interface
my $author; # Author of gallery
my $id; # Gallery ID
my $name; # Gallery/Work name
my $header; # HTML Header
#####################
# Program area
# Retrieve header
($header) = $database->DocumentGet('GalleryHeader');
# Tree link handling
# Base link
if ((defined($sparam->{'SUB'}))
&& (length($sparam->{'SUB'}) > 3))
{
# The root
# Self referencing link
$link = $database->{'SYS'}{'LnkIntGallery'};
# Template
$tree = $tmpl->Pass('TagTree',
MNAME => '',
MLINK => $link
);
# Listing for genre
# Additional link
$link .= '/' . $sparam->{'TYP'}
. '/' . $sparam->{'SUB'};
# Template
$tree .= $tmpl->Pass('TagTree',
MNAME => $sparam->{'SUB'},
MLINK => $link
);
if ((defined($sparam->{'GRE'}))
&& (length($sparam->{'GRE'}) > 3))
{
# Listing for galleries
# Additional link
$link .= '/' . $sparam->{'GRE'};
# Template
$tree .= $tmpl->Pass('TagTree',
MNAME => $sparam->{'GRE'},
MLINK => $link
);
}
}
# Check for rewrite
if ((defined($sparam->{'GAL'}))
&& ($sparam->{'GAL'} =~ /^\d+$/))
{
# Gallery details
# Pull details
($id, $author, $name) = $database->DataGet("SELECT
GalleryID,
GalleryPenName,
GalleryName
FROM Gallery
WHERE GalleryID=?", $sparam->{'GAL'});
# Addition to the tree
if (defined($name))
{
# Listing for galleries
if (defined($tree))
{
# Additional link
$link .= '/' . $sparam->{'GAL'};
# Template
$tree .= $tmpl->Pass('TagTree',
MNAME => $name,
MLINK => $link
);
}
# Work takes over title
if ((defined($sparam->{'WRK'}))
&& ($sparam->{'WRK'} =~ /^\d+$/))
{
# Pull details
($id, $author, $name) = $database->DataGet("SELECT
g.GalleryID,
g.GalleryPenName,
w.WorkName
FROM Gallery g, Work w
WHERE w.GalleryID=g.GalleryID
AND g.GalleryID=?
AND w.WorkID=?",
$sparam->{'GAL'},
$sparam->{'WRK'}
);
# Replace if need be
if (defined($name))
{
# Listing for galleries
if (defined($tree))
{
# Additional link
$link .= '/' . $sparam->{'WRK'};
# Template
$tree .= $tmpl->Pass('TagTree',
MNAME => $name,
MLINK => $link
);
}
# Reset title
$database->{'TITLE'} = "$name by $author";
}
}
# Galleries
# This is the default
else
{
# Reset title
$database->{'TITLE'} = "$author: $name";
}
}
}
# Safety
$tree = (defined($tree))
? $tree
: $gal->{'TagTreeBlank'};
# Replace
$header =~ s/MTREE/$tree/gs;
# Print out modified header
print $menu->Rewrite($header);
}
#####################
# Navigation
#
# Used to consolidate navigational methods on the site employing OFFSET and LIMIT
# which are available on PostgreSQL.
sub Navigation
{
#####################
# Data members
my $tmpl = shift; # Template handler
my $gal = shift; # Gallery hash
my $display = shift; # Entries to show off
my $total = shift; # Total entries
my $offset = shift; # Current position
my $url = shift; # Link to display
my $inline = shift; # Inline parameters
my $count; # Basic counter
my $frst; # First entry
my $last; # Last entry
my $next; # Next entry
my $prev; # Prev entry
my $link; # Generated link
my $nav; # Completed navigational page
my $pass; # What is passed
#####################
# Program area
# Set values
$count = 0;
$nav = '';
$pass = ' ';
# Calculate next and previous
$frst = 1;
$last = (($total - ($total % $display)) / $display) + 1;
$prev = (($offset - 1) > 0) ? $offset - 1 : 1;
$next = (($offset + 1) <= $last) ? $offset + 1 : $last;
# Loop
do
{
# Remove mount to verify spacing
$total -= $display;
# Increment
$count++;
# Assign
$link = $url . '/' . $count . $inline;
# Append
$nav .= ($offset == $count)
? $tmpl->Pass('TagNavView', MNAME=>$count, MLINK=>$link)
: $tmpl->Pass('TagNav', MNAME=>$count, MLINK=>$link);
} while ($total > 0);
# Generate template
# Only if there is a need
$pass = $tmpl->Pass('TagNav', MNAME=>$gal->{'TxtFirst'}, MLINK=>$url . '/' . $frst . $inline)
. $tmpl->Pass('TagNav', MNAME=>$gal->{'TxtPrev'}, MLINK=>$url . '/' . $prev . $inline)
. $nav
. $tmpl->Pass('TagNav', MNAME=>$gal->{'TxtNext'}, MLINK=>$url . '/' . $next . $inline)
. $tmpl->Pass('TagNav', MNAME=>$gal->{'TxtLast'}, MLINK=>$url . '/' . $last . $inline) if ($count > 1);
# Return completed
return $pass;
}
#####################
# Pen Names
#
# Will take a list of all contributors and make it in such a way that it
# can display all of the contributors on one line.
sub PenNames
{
#####################
# Data members
my $database = shift; # Database handler
my $param = shift; # Parameter list
my $tmpl = shift; # Template handler
my $gal = shift; # Gallery parameter
my $id = shift; # Gallery ID
my $inline = shift; # Predefined inlines
my $owner = shift; # Rightful owner
my $count; # Basic counter
my $entries; # Number entries
my $ibio; # Link to the bio
my $consol; # Consolidated lines
my $spacer; # Employed spacer
my @args; # Arguments to send
my @contribs; # Complete list of contributors
#####################
# Program area
# Owner of gallery
# Owner specified
if (defined($owner))
{
# Pass arguments
push(@args, $id, $owner);
# Throw in additional formatting
$owner = 'AND PuppeteerLogin=? ';
}
# Normal dual entry
else
{
# Normal passage
push(@args, $id);
# Nothing to see
$owner = '';
}
# Pull list of all contributors
$database->GetList(\@contribs, "SELECT PuppetName
FROM GalleryAccess
WHERE GalleryID=? $owner
ORDER BY AccessOwner DESC, PuppetName", @args);
# Amount of entries
$entries = @contribs;
# Initiate
$consol = '';
# Loop and search
for ($count=0; $count < $entries; $count++)
{
# Generate biographical link
$ibio = '/' . join('', $database->DataGetPuppetShortname($contribs[$count])) . '/system' . $inline;
# Information handling
# Initialize
if ($count == 0)
{
# Set authors information first
$consol .= $tmpl->Pass('TagPenName',
MNAME => $contribs[$count],
MLINK => $database->{'SYS'}{'LnkIntBio'} . $ibio
);
}
# Appending
else
{
# Spacer
$spacer = ($count != ($entries-1))
? $gal->{'TagPenNameSpacer'}
: $gal->{'TagPenNameFinalize'};
# Additional contributors
$consol .= $spacer . $tmpl->Pass('TagPenName',
MNAME => $contribs[$count],
MLINK => $database->{'SYS'}{'LnkIntBio'} . $ibio
);
}
}
# Return consolidated line
return $consol;
}
#####################
# Work Detail
#
# Work display allows a user to view the works themselves in full
# detail.
sub WorkDetail
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $option; # Option handler
my $layer; # Layer management
my $res; # Results
my $revisions; # Query for revisions
my $statement; # Query statement
my $cmnt; # Comment preferences
my $name; # Verification check
my $type; # Gallery type
my $view; # Type of view
my $order; # Sort order
my $sort; # Sort type
my $comments; # Comments template
my $descr; # Description
my $pen; # Pen names formatted
my $work; # Work template
my $next = 0; # Next sequence
my $curr = 0; # Current position
my $prev = 0; # Previous record
my $totl = 0; # Total amount of works
my $rate; # Rating
my $user; # Username
my $vote; # Votes
my $url; # Self referencing link
my $inline; # Inline parameters
my @seq; # Logical squence
#####################
# Program Area
# Things are in order
($name) = $database->DataGetWorkName($sparam->{'WRK'}, $sparam->{'GAL'});
# Continue as planned
if (defined($name))
{
# Things are proper
return 0 unless (CheckAuth($database, $login, $param, $sparam, $tmpl, $gal));
# Create instance
$option = new Ethereal::Option;
# Determine layer handling
$layer = ($sparam->{'LYR'} > 0)
? 'AND WorkLayer=' . $sparam->{'LYR'}
: 'AND WorkLayer IS NULL';
# Information gathering
# Retreive gallery basics
($sort, $cmnt, $type, $user) = $database->DataGet("SELECT
GallerySort,
GalleryComments,
GalleryType,
PuppeteerLogin
FROM Gallery
WHERE GalleryID=?",
$sparam->{'GAL'}
);
# Ordering type
$order = $option->GallerySortReal($sort);
# Retrieve next of kin
$database->GetList(\@seq, "SELECT WorkID
FROM Work
WHERE GalleryID=? $layer
AND WorkID > 1
ORDER BY $order",
$sparam->{'GAL'}
);
# Total
$totl = @seq;
# Where we are
for ($curr=0; $curr < $totl; $curr++)
{
# Find and leave loop
last unless ($seq[$curr] != $sparam->{'WRK'});
}
# Position of cousins
$next = ($curr+1 >= $totl) ? $seq[0] : $seq[$curr+1];
$prev = $seq[$curr-1];
# Linking
# Fetch link
$url = $database->{'SYS'}{'LnkIntGallery'} . '/'
. $cgi->escape($sparam->{'TYP'}) . '/'
. $cgi->escape($sparam->{'SUB'}) . '/'
. $cgi->escape($sparam->{'GRE'}) . '/'
. $sparam->{'GAL'} . '/'
. $sparam->{'LYR'};
# Inline parameters general
$inline = (defined($param->{'USER'}))
? $param->EmbedInline(USER=>$param->{'USER'}, CRYPT=>$param->{'CRYPT'})
: '';
# Works of art
# Retrieve rating
($rate, $vote) = $database->DataGetWorkAvg($sparam->{'WRK'}, $sparam->{'GAL'});
# Prepare and execute
$database->Pull(\$statement, "SELECT
PuppeteerLogin AS \"WorkOwner\",
WorkName AS \"WorkName\",
WorkDescription AS \"WorkDescription\",
WorkSort AS \"WorkSort\",
WorkImage AS \"WorkImage\",
WorkImageThumbnail AS \"WorkImageThumbnail\",
WorkImageSize AS \"WorkImageSize\",
WorkImageWidth AS \"WorkImageWidth\",
WorkImageHeight AS \"WorkImageHeight\",
WorkImageView AS \"WorkImageView\",
WorkImageFull AS \"WorkImageFull\",
WorkImageExif AS \"WorkImageExif\",
WorkText AS \"WorkText\",
WorkTextPreserve AS \"WorkTextPreserve\",
getDate(WorkTimestamp) AS \"WorkTimestamp\"
FROM Work
WHERE WorkID=?
AND GalleryID=?",
$sparam->{'WRK'},
$sparam->{'GAL'}
);
# Make available
if ($res = $statement->fetchrow_hashref())
{
# Fork for gallery styles
# Image gallery
if ($type eq 'image')
{
# Exif information
my $exif = (defined($res->{'WorkImageExif'}))
? $tmpl->Pass('TmplImageExif', MEXIF=>$res->{'WorkImageExif'})
: '';
# View related plesantries
# Full view
if ((defined($sparam->{'POS'}))
&& ($sparam->{'POS'} eq 'full'))
{
# Adjust link to work
$view = $res->{'WorkImage'};
# Replace appropriatly
$view =~ s/^(.+\/)(view-)(work\.\w+)$/$1$3/;
# Display image specific
# Full view
$work = $tmpl->Pass('TmplImageWork',
LSTEXIF => $exif,
LIMAGE => $view,
LTOGGLE => $url . '/' . $sparam->{'WRK'},
MNAME => $res->{'WorkName'},
MWDHT => $res->{'WorkImageFull'},
MTOGGLE => $gal->{'TagImageView'}
);
}
# Regular view
else
{
# Display image specific
# Normal view
$work = $tmpl->Pass('TmplImageWork',
LSTEXIF => $exif,
LIMAGE => $res->{'WorkImage'},
LTOGGLE => $url . '/' . $sparam->{'WRK'} . '/full',
MNAME => $res->{'WorkName'},
MWDHT => $res->{'WorkImageView'},
MTOGGLE => $gal->{'TagImageFull'}
);
}
}
# Text based galleries
elsif ($type eq 'text')
{
# Local variables
my ($rdate, $rstamp);
# Initial assignment
my $print = '';
my $revs = '';
my $post = $res->{'WorkText'};
# Make use of revision instead
if ((defined($sparam->{'POS'}))
&& ($sparam->{'POS'} =~ /^\w{30,}/))
{
# Make use of revision
($post, $rdate) = $database->DataGet("SELECT
RevisionText,
getDate(RevisionTimestamp)
FROM Revision
WHERE WorkID=?
AND GalleryID=?
AND RevisionTimestamp=?",
$sparam->{'WRK'},
$sparam->{'GAL'},
pack('H*', $sparam->{'POS'})
);
# Append notice
$post .= $tmpl->Pass('TagRevNotice',
MDATE => $rdate
);
}
# Rewriting
# Basic replacements
$post =~ s/$/\n/;
# Maintain spacing
$post =~ s/\n/
/gs;
# Revision control
if ($type eq 'text')
{
# Pull new list
$database->Pull(\$revisions, "SELECT
RevisionTimestamp AS \"Timestamp\",
getDate(RevisionTimestamp) AS \"Date\"
FROM Revision
WHERE WorkID=?
AND GalleryID=?",
$sparam->{'WRK'},
$sparam->{'GAL'}
);
# Verification
if (($rstamp, $rdate) = $revisions->fetchrow())
{
# Initialize template
$revs = $gal->{'TagRevTitle'};
# Initial link
$revs .= $tmpl->Pass('TagRevLink',
MLINK => $url . '/' . $sparam->{'WRK'} . $inline,
MNAME => $gal->{'TxtRecent'}
);
# Check first
do
{
# Append additional links
$revs .= $tmpl->Pass('TagRevLink',
MLINK => $url . '/' . $sparam->{'WRK'} . '/' . unpack('H*', $rstamp) . $inline,
MNAME => $rdate
);
} while (($rstamp, $rdate) = $revisions->fetchrow());
# Close off
$revs .= $gal->{'TagRevClose'};
# Close handle
$revisions->finish();
}
}
# Printing option
if (-f "$database->{SYS}{SetGalleryRoot}/$sparam->{GAL}/$sparam->{WRK}/work.pdf")
{
# Show print option
$print = $tmpl->Pass('TagPrint',
MLINK => "$database->{SYS}{SetGalleryLink}/$sparam->{GAL}/$sparam->{WRK}/work.pdf"
);
}
# Display image specific
$work = $tmpl->Pass('TmplTextWork',
MTEXT => $post,
MREVS => $revs,
MPRINT => $print
);
}
# Additional information
# List comments
$comments = CommentDisplay(
$database,
$login,
$cgi,
$param,
$tmpl,
$sparam,
$gal,
$gal->{'SetRetrieve'}
);
# Pen names
$pen = PenNames(
$database,
$param,
$tmpl,
$gal,
$sparam->{'GAL'},
$inline,
$res->{'WorkOwner'}
);
# Establishment of views
$view = ($sparam->{'POS'} eq 'full')
? '/full'
: '';
# Safety
$descr = (defined($res->{'WorkDescription'}))
? $res->{'WorkDescription'}
: $gal->{'TxtDescription'};
# Common display
# Header
$tmpl->Show('TmplWork',
MAUTHOR => $pen,
MCOMMENT => $comments,
MCURR => $curr+1,
MDESC => $descr,
MNAME => $res->{'WorkName'},
MWORK => $work,
MTOTAL => $totl,
LGTOP => $url . '/' . $inline,
LNEXT => $url . '/' . $next . $view . $inline,
LPREV => $url . '/' . $prev . $view . $inline
);
}
# Finish query
$statement->finish();
}
# Signal error
else
{
# Invalid entry
$tmpl->Show('TmplMsg', MMESSAGE=>$gal{'MsgParam'});
}
}
#####################
# Work Listing
#
# Work listing will allow casual viewers to see an overview of every
# work available. This includes a naivgational system, and an overview of
# the more recent comments made on works.
sub WorkList
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $filter; # Filtering options
my $option; # Option handler
my $gsth; # Gallery query
my $lsth; # Link query
my $msth; # Map query
my $nsth; # News query
my $ssth; # Layers query
my $wsth; # Works query
my $gres; # Information on gallery
my $lres; # Link results page
my $mres; # Mapping results
my $nres; # Information on news items
my $sres; # Information on layers
my $wres; # Information on works
my $descr; # Description
my $length; # Text length
my $rating; # Rating
my $thumb; # Thumbnail config
my $expand; # Expansion handling
my $layer; # Layer to search through
my $newness; # Newness factor
my $offset; # Where to start from
my $order; # Searching order
my $parent; # Parent layer
my $total; # Entries to look out for
my $user; # Username of owner
my $watch; # Watch gallery
my $authors; # Author management
my $comments; # Comments template
my $genres; # Formatted genres
my $intro; # Intro section
my $layers; # Layer page
my $links; # Links page
my $map; # The map action button/menu
my $news; # News entry
my $page; # Navigational page
my $single; # Single line to work with
my $works; # Works page
my $int_id; # Intro's used identifier
my $int_name; # Intro's used name
my $int_descr; # Intro's used description
my $int_level; # Intro's used level
my $int_light; # Intro's used highlight
my $int_short; # Intro's used short name
my $int_thumb; # Intro's used thumbnail
my $inline; # Inline parameters
my $iwatch; # Puppet watch option
my $link_work; # Link pertaining to works
my $link; # Managed link
my @genres; # Multiple genres
my @layers = qw(Zero One Two Three Four Five); # Levels for layers
my @levels; # Levels captured
my %pass; # Temporary passthrough for parameters
#####################
# Program Area
# Authentication
# Exit unless things are proper
return 0 unless (CheckAuth($database, $login, $param, $sparam, $tmpl, $gal));
# Create instance
$option = new Ethereal::Option();
# Safety
$sparam->{'LYR'} = 0
unless ((defined($sparam->{'LYR'}))
&& ($sparam->{'LYR'} =~ /^(\d+|map)$/));
# Work cannot be defined
# If made it this far
$sparam->{'WRK'} = 0;
# Link management
# Generate primary working link
$link = $database->{'SYS'}{'LnkIntGallery'} . '/'
. $cgi->escape($sparam->{'TYP'}) . '/'
. $cgi->escape($sparam->{'SUB'}) . '/'
. $cgi->escape($sparam->{'GRE'}) . '/'
. $sparam->{'GAL'};
# Generate link required for works
$link_work = $database->{'SYS'}{'LnkIntGallery'} .'/'
. $cgi->escape( $sparam->{'TYP'}) . '/'
. $cgi->escape($sparam->{'SUB'}) . '/'
. $cgi->escape($sparam->{'GRE'}) . '/'
. $sparam->{'GAL'} . '/'
. $sparam->{'LYR'};
# Inline parameters general
$inline = (defined($param->{'USER'}))
? $param->EmbedInline(USER=>$param->{'USER'}, CRYPT=>$param->{'CRYPT'})
: '';
# Mapping option
# General to both
$map = $tmpl->Pass('TagNav',
MNAME => $gal->{'TxtMap'},
MLINK => $link . '/map' . $inline
);
# Base information
# Gallery information
$database->Pull(\$gsth, "SELECT
PuppeteerLogin AS \"PuppeteerLogin\",
GalleryName AS \"GalleryName\",
GalleryRating AS \"GalleryRating\",
GalleryDescription AS \"GalleryDescription\",
GalleryHighlight AS \"GalleryHighlight\",
GalleryThumbnail AS \"GalleryThumbnail\",
GallerySort AS \"GallerySort\",
GalleryType AS \"GalleryType\",
GalleryComments AS \"GalleryComments\",
GalleryDisplay AS \"GalleryDisplay\",
getDate(GalleryCreated) AS \"GalleryCreated\",
getDate(GalleryUpdated) AS \"GalleryUpdated\"
FROM Gallery
WHERE GalleryID=?",
$sparam->{'GAL'}
);
# Common controls without depth
# Check values
if ($gres = $gsth->fetchrow_hashref())
{
# Genres
# Genre searching
$database->GetListEstablished(\@genres, $sparam->{'GAL'});
# Format genre line
$genres = join("/", @genres);
# Authors
# Determine authors
$authors = PenNames(
$database,
$param,
$tmpl,
$gal,
$sparam->{'GAL'},
$inline
);
# Watchful processing
# Watch allows the notification of changes to user
if (defined($param->{'USER'}))
{
# Determine watch
($watch) = $database->DataGetGalleryWatch($sparam->{'GAL'}, $param->{'USER'});
# Toggle watch
if (defined($param->{'WATCH'}))
{
# Change standing behaviour
if (defined($watch))
{
# Remove database entry
$database->Quick("DELETE FROM GalleryNotify
WHERE GalleryID=?
AND PuppeteerLogin=?",
$sparam->{'GAL'},
$param->{'USER'}
);
# Change logic
$watch = undef;
}
else
{
# Create entry
$database->Quick("INSERT INTO GalleryNotify
(GalleryID,
PuppeteerLogin)
VALUES (?,?)",
$sparam->{'GAL'},
$param->{'USER'}
);
# Change logic
$watch = $param->{'USER'};
}
# Cleanup
$param->Cleanup('WATCH');
}
# Generate inline
$iwatch = $param->EmbedInline(
USER => $param->{'USER'},
CRYPT => $param->{'CRYPT'},
WATCH => 'True'
);
# Change langauge
$watch = (defined($watch))
? $tmpl->Pass('TagGalIgnore', MLINK=>$link . $iwatch)
: $tmpl->Pass('TagGalWatch', MLINK=>$link . $iwatch);
}
# Safety
# Generate widget
$watch = $tmpl->Pass('TagGalWatch', MLINK=>"$link\?USER\=\&WATCH\=True")
unless (defined($watch));
}
# Pull in values
# Do not show a site map
if ((defined($gres))
&& ($sparam->{'LYR'} =~ /^\d+$/))
{
# Assign username
$user = $gres->{'PuppeteerLogin'};
# Sorting order
# Ordering type
$order = $option->GallerySortReal($gres->{'GallerySort'});
# Offset management
# Starting point
$sparam->{'POS'} = 1
unless ((defined($sparam->{'POS'}))
&& ($sparam->{'POS'} =~ /^\d+$/));
# Offset
$offset = ($sparam->{'POS'} - 1) * $gres->{'GalleryDisplay'};
# Layer handling
$layer = ($sparam->{'LYR'} > 0)
? 'AND WorkLayer=' . $sparam->{'LYR'} . ' '
: 'AND WorkLayer IS NULL ';
# Layer information
if ($sparam->{'LYR'} != 0)
{
# Get specific information in case
($int_id,
$int_short,
$int_name,
$int_descr,
$int_light,
$int_thumb,
$int_level,
@levels) = $database->DataGet("SELECT
LayerID AS \"LayerID\",
LayerShort AS \"LayerShort\",
LayerFull AS \"LayerFull\",
LayerDescription AS \"LayerDescription\",
LayerHighlight AS \"LayerHighlight\",
LayerThumbnail AS \"LayerThumbnail\",
LayerLevel AS \"LayerLevel\",
LevelZero AS \"LevelZero\",
LevelOne AS \"LevelOne\",
LevelTwo AS \"LevelTwo\",
LevelThree AS \"LevelThree\",
LevelFour AS \"LevelFour\",
LevelFive AS \"LevelFive\"
FROM Layer
WHERE GalleryID=?
AND LayerID=?",
$sparam->{'GAL'},
$sparam->{'LYR'}
);
# Determine parent
$parent = $levels[$int_level-1] if ($int_level > 0);
}
# Make sure information is present
# Else override with gallery information
$int_descr = (defined($int_descr)) ? $int_descr : $gres->{'GalleryDescription'};
$int_light = (defined($int_light)) ? $int_light : $gres->{'GalleryHighlight'};
$int_name = (defined($int_name)) ? $int_name : $gres->{'GalleryName'};
# Images may have issues
$int_thumb = (defined($int_thumb)) ? $int_thumb : $gres->{'GalleryThumbnail'};
$int_thumb = (defined($int_thumb)) ? $int_thumb : $gal->{'SetImgBlank'};
# No description then put one in
$int_descr = (defined($int_descr)) ? $int_descr : $gal->{'TxtDescription'};
# Embeded Layers
# No need for a sub-page
if ($sparam->{'POS'} == 1)
{
# Safety
$int_level = (defined($int_level)) ? $int_level : 0;
# Expand query as necessary
$expand = (defined($int_id))
? "AND LayerLevel=" . ($int_level+1) . " AND Level$layers[$int_level]=" . DBI::neat($int_short)
: "AND LayerLevel=" . $int_level;
# Prepare query as these are
# general to both types
$database->Pull(\$ssth, "SELECT
LayerID AS \"LayerID\",
LayerFull AS \"LayerFull\",
LayerDescription AS \"LayerDescription\",
LayerThumbnail AS \"LayerThumbnail\"
FROM Layer
WHERE GalleryID=? $expand
ORDER BY LayerFull",
$sparam->{'GAL'}
);
}
# Specific type processing
# Image galleries
if ($gres->{'GalleryType'} eq 'image')
{
# Information display
# Intro and summary
$intro = $tmpl->Pass('TmplImageIntro',
MDESCR => $int_descr,
MHLIGHT => $int_light,
MTHUMB => $int_thumb,
MGENRE => $genres,
MAUTHOR => $authors,
MRATING => $gres->{'GalleryRating'},
MTITLE => $int_name,
MCREATED => $gres->{'GalleryCreated'},
MUPDATED => $gres->{'GalleryUpdated'},
MWATCH => $watch
);
# Work information
# Amount of works
($total) = $database->DataGet("SELECT COUNT(*)
FROM Work
WHERE GalleryID=?
AND WorkImage IS NOT NULL $layer",
$sparam->{'GAL'}
);
# Capture nav line
$page = Navigation(
$tmpl,
$gal,
$gres->{'GalleryDisplay'},
$total,
$sparam->{'POS'},
$link . '/' . $sparam->{'LYR'} .'/',
$inline
);
# Layer management
if (defined($ssth))
{
# Parent return
# Parent is a layer
if (defined($parent))
{
# Get specific information in case
($int_id,
$int_name,
$int_descr,
$int_light,
$int_thumb) = $database->DataGet("SELECT
LayerID AS \"LayerID\",
LayerFull AS \"LayerFull\",
LayerDescription AS \"LayerDescription\",
LayerHighlight AS \"LayerHighlight\",
LayerThumbnail AS \"LayerThumbnail\",
LayerLevel AS \"LayerLevel\"
FROM Layer
WHERE GalleryID=?
AND LayerShort=?",
$sparam->{'GAL'},
$parent
);
# Make sure thumnail is assigned
$thumb = (defined($int_thumb))
? $int_thumb
: $gal->{'SetImgBlank'};
# Layer has a layer parent
$works = $tmpl->Pass('TmplImageLayer',
MNAME => $int_name,
MDESCR => $int_descr,
MIMAGE => $thumb,
MTYPE => $gal->{'SetLayerParent'},
MLINK => $link . '/' . $int_id . $inline
);
}
# Parent is the root
elsif ((!defined($parent))
&& ($sparam->{'LYR'} != 0))
{
# Make sure thumnail is assigned
$thumb = (defined($gres->{'GalleryThumbnail'}))
? $gres->{'GalleryThumbnail'}
: $gal->{'SetImgBlank'};
# Layer has the root as a parent
$works = $tmpl->Pass('TmplImageLayer',
MNAME => $gres->{'GalleryName'},
MDESCR => $gres->{'GalleryDescription'},
MIMAGE => $gres->{'GalleryThumbnail'},
MTYPE => $gal->{'SetLayerParent'},
MLINK => $link . $inline
);
}
# Children layers
# Loop and manage
while ($sres = $ssth->fetchrow_hashref())
{
# Make sure thumnail is assigned
$thumb = (defined($sres->{'LayerThumbnail'}))
? $sres->{'LayerThumbnail'}
: $gal->{'SetImgBlank'};
# Generate template
# Store for addition into main list
$works .= $tmpl->Pass('TmplImageLayer',
MNAME => $sres->{'LayerFull'},
MDESCR => $sres->{'LayerDescription'},
MIMAGE => $thumb,
MTYPE => $gal->{'SetLayerChild'},
MLINK => $link . '/' . $sres->{'LayerID'} . $inline
);
}
# End query
$ssth->finish();
}
# Works
# Prepare query
$database->Pull(\$wsth, "SELECT
WorkID AS \"WorkID\",
WorkName AS \"WorkName\",
WorkDescription AS \"WorkDescription\",
WorkRating AS \"WorkRating\",
WorkImageThumbnail AS \"WorkImageThumbnail\",
WorkImageSize AS \"WorkImageSize\",
WorkImageWidth AS \"WorkImageWidth\",
WorkImageHeight AS \"WorkImageHeight\",
WorkImageView AS \"WorkImageView\",
WorkImageFull AS \"WorkImageFull\",
getDate(WorkTimestamp) AS \"WorkTimestamp\",
getNew(WorkTimestamp) AS \"WorkNewness\"
FROM Work
WHERE GalleryID=?
AND WorkImage IS NOT NULL $layer
ORDER BY \"WorkNewness\" DESC, $order
LIMIT $gres->{GalleryDisplay}
OFFSET $offset",
$sparam->{'GAL'}
);
# Test the waters
# Cycle through
while ($wres = $wsth->fetchrow_hashref())
{
# Tag adjustements
# Newness tag
$newness = ($wres->{'WorkNewness'} != 0)
? $gal->{'TagNewness'}
: '';
# If need exists
if (($gres->{'GalleryComments'} eq 'comment')
|| ($gres->{'GalleryComments'} eq 'combo'))
{
# Caculate
$rating = $wres->{'WorkRating'};
}
else
{
# Assign nil
$rating = $gal->{'SetNil'};
}
# Generate template
# Store for addition into main list
$works .= $tmpl->Pass('TmplImageList',
MNAME => $wres->{'WorkName'},
MDESCR => $wres->{'WorkDescription'},
MIMAGE => $wres->{'WorkImageThumbnail'},
MLINK => $link_work . '/' . $wres->{'WorkID'} . $inline,
MRATING => $rating,
MSIZE => $wres->{'WorkImageSize'},
MHEIGHT => $wres->{'WorkImageHeight'},
MWIDTH => $wres->{'WorkImageWidth'},
MTHUMB => $database->{'SYS'}{'SetThumbnail'},
MVIEW => $wres->{'WorkImageView'},
MUPDATED => $wres->{'WorkTimestamp'},
MNEWNESS => $newness,
MWINDOW => 'WIN' . $sparam->{'GAL'} . 'x' . $sparam->{'LYR'}
);
}
# Finish query
$wsth->finish();
}
# Text based galleries
elsif ($gres->{'GalleryType'} eq 'text')
{
# Information display
# Intro and summary
$intro = $tmpl->Pass('TmplTextIntro',
MDESCR => $int_descr,
MGENRE => $genres,
MAUTHOR => $authors,
MRATING => $gres->{'GalleryRating'},
MTITLE => $int_name,
MCREATED => $gres->{'GalleryCreated'},
MUPDATED => $gres->{'GalleryUpdated'},
MWATCH => $watch
);
# Work information
# Calculate totals
($total) = $database->DataGet("SELECT COUNT(*)
FROM Work
WHERE GalleryID=?
AND WorkText IS NOT NULL $layer",
$sparam->{'GAL'}
);
# Capture nav line
$page = Navigation(
$tmpl,
$gal,
$gres->{'GalleryDisplay'},
$total,
$sparam->{'POS'},
$link . '/' . $sparam->{'LYR'} . '/',
$inline
);
# Layer management
if (defined($ssth))
{
# Parent return
# Parent is a layer
if (defined($parent))
{
# Get specific information in case
($int_id,
$int_name,
$int_descr) = $database->DataGet("SELECT
LayerID AS \"LayerID\",
LayerFull AS \"LayerFull\",
LayerDescription AS \"LayerDescription\"
FROM Layer
WHERE GalleryID=?
AND LayerID=?",
$sparam->{'GAL'},
$parent
);
# Layer has a layer parent
$works = $tmpl->Pass('TmplTextLayer',
MNAME => $int_name,
MDESCR => $int_descr,
MTYPE => $gal->{'SetLayerParent'},
MLINK => $link . '/' . $int_id . $inline
);
}
# Parent is the root
elsif ((!defined($parent))
&& ($sparam->{'LYR'} != 0))
{
# Layer has the root as a parent
$works = $tmpl->Pass('TmplTextLayer',
MNAME => $gres->{'GalleryName'},
MDESCR => $gres->{'GalleryDescription'},
MTYPE => $gal->{'SetLayerParent'},
MLINK => $link . $inline
);
}
# Loop and manage
while ($sres = $ssth->fetchrow_hashref())
{
# Generate template
# Store for addition into main list
$works .= $tmpl->Pass('TmplTextLayer',
MNAME => $sres->{'LayerFull'},
MDESCR => $sres->{'LayerDescription'},
MTYPE => $gal->{'SetLayerChild'},
MLINK => $link . '/' . $sres->{'LayerID'} . $inline
);
}
# End query
$ssth->finish();
}
# Work management
# Detailed information
$database->Pull(\$wsth, "SELECT
WorkID AS \"WorkID\",
WorkName AS \"WorkName\",
WorkDescription AS \"WorkDescription\",
WorkRating AS \"WorkRating\",
WorkText AS \"WorkText\",
getDate(WorkTimestamp) AS \"WorkTimestamp\",
getNew(WorkTimestamp) AS \"WorkNewness\"
FROM Work
WHERE GalleryID=?
AND WorkText IS NOT NULL $layer
ORDER BY \"WorkNewness\" DESC, $order
LIMIT $gres->{GalleryDisplay}
OFFSET $offset",
$sparam->{'GAL'}
);
# Create instance
$filter = new Ethereal::Filter();
# Safety check
while ($wres = $wsth->fetchrow_hashref())
{
# Newness tag
$newness = ($wres->{'WorkNewness'} != 0)
? $gal->{'TagNewness'}
: '';
# Tag assignments
# If need exists
if (($gres->{'GalleryComments'} eq 'comment')
|| ($gres->{'GalleryComments'} eq 'combo'))
{
# Calculate
$rating = $wres->{'WorkRating'};
}
else
{
# Assign nil
$rating = $gal->{'SetNil'};
}
# Description
$descr = $wres->{'WorkDescription'};
$descr = (defined($descr))
? $descr
: $filter->StripHTML(substr(DBI::neat($wres->{'WorkText'}, 252), 1, -1));
# Length
$length = length($wres->{'WorkText'});
# Display
$works .= $tmpl->Pass('TmplTextList',
MNAME => $wres->{'WorkName'},
MDESCR => $descr,
MLENGTH => format_number($length, 0),
MLINK => $link_work . '/' . $wres->{'WorkID'} . $inline,
MRATING => $rating,
MUPDATED => $wres->{'WorkTimestamp'},
MNEWNESS => $newness,
MWINDOW => 'WIN' . $sparam->{'GAL'} . 'x' . $sparam->{'LYR'}
);
}
# Finish query
$wsth->finish();
}
# Additional features
# Generate and display
if (($sparam->{'POS'} == 1)
&& ($sparam->{'LYR'} == 0))
{
# Gallery Comments
# Passing of temporary values
%pass = (%{$sparam}, WRK=>0);
# Comments
# Initialize
$comments = '';
# List comments
$comments = CommentDisplay(
$database,
$login,
$cgi,
$param,
$tmpl,
\%pass,
$gal,
$gal->{'SetRetrieve'}
);
# News Items
# Initalize
$news = '';
# Expansion handling
$expand = (defined($param->{'EXPAND'}))
? ''
: 'LIMIT 5';
# Prepare query
$database->Pull(\$nsth, "SELECT
CommentID AS \"CommentID\",
CommentPost AS \"CommentPost\",
getDate(CommentTimestamp) AS \"CommentTimestamp\"
FROM Comment
WHERE GalleryID=?
AND WorkID=1
ORDER BY CommentTimestamp DESC $expand", $sparam->{'GAL'});
# Pull information
# Verify need
if ($nres = $nsth->fetchrow_hashref())
{
# Ability to expand
$expand = $param->EmbedInline($param->Flat(), EXPAND=>'True');
$expand = $link . '/' . $sparam->{'LYR'} . $expand;
# Self referencing links
my $idelete = '';
my $ldelete = $database->{'SYS'}{'LnkIntGallery'} . '/comment/' . $sparam->{'GAL'} . '/' . 1;
# Initialize
$single = '';
# Loop and display
do
{
# Check for need to generate
$idelete = $tmpl->Pass('TagDelete',
MLINK => $ldelete . '/' . $nres->{'CommentID'} . $inline
) if ((defined($param->{'USER'})) && ($user eq $param->{'USER'}));
# Display
$single .= $tmpl->Pass('TmplQNewsEntry',
MDATE => $nres->{'CommentTimestamp'},
MTEXT => $nres->{'CommentPost'},
MDELL => $idelete
);
} while ($nres = $nsth->fetchrow_hashref());
# Run through final template
$news .= $tmpl->Pass('TmplQNews',
LSTNEWS => $single,
LNEXP => $expand
);
}
# Finish query
$nsth->finish();
# Quick Links
# Initalize
$links = '';
# Prepare retreival
$database->Pull(\$lsth, "SELECT
LinkName AS \"LinkName\",
LinkAddress AS \"LinkAddress\"
FROM Link
WHERE GalleryID=?
ORDER BY LinkName",
$sparam->{'GAL'}
);
# Check and initial setup
if ($lres = $lsth->fetchrow_hashref())
{
# Intialize
$single = '';
# Loop and populate main body
do
{
# Display
$single .= $tmpl->Pass('TmplQLinksEntry',
MLINK => $lres->{'LinkAddress'},
MNAME => $lres->{'LinkName'}
);
} while ($lres = $lsth->fetchrow_hashref());
# Generate final template
$links .= $tmpl->Pass('TmplQLinks',
LSTLINKS => $single
);
}
# Finish query
$lsth->finish();
# Is there still a need
# All necessary components in place
if ((length($news) > 5)
&& (length($links) > 5))
{
# Complete view
$tmpl->Show('TmplListingPri',
MINTRO => $intro,
MNAV => $page,
MMAP => $map,
MNEWS => $news,
MQUICK => $links,
MCOMMENT => $comments,
LSTWORKS => $works
);
}
else
{
# Simplified view
$tmpl->Show('TmplListingSec',
MINTRO => $intro,
MNAV => $page,
MMAP => $map,
LSTWORKS => $works
);
}
}
# Simple view
# Simply display appropriate template
else
{
# Display final work
# Simplified view
$tmpl->Show('TmplListingSec',
MINTRO => $intro,
MNAV => $page,
MMAP => $map,
LSTWORKS => $works
);
}
}
# Do not show a site map
elsif ((defined($gres))
&& ($sparam->{'LYR'} =~ /^map$/))
{
# Pull necessary information for data map
$database->Pull(\$msth, "SELECT
l.LayerID AS \"LayerID\",
l.LayerFull AS \"LayerFull\",
l.LayerLevel AS \"LayerLevel\",
COUNT(w.GalleryID) AS \"LayerCount\"
FROM Layer l
LEFT OUTER JOIN Work w
ON (l.GalleryID=w.GalleryID AND l.LayerID=w.WorkLayer)
WHERE l.GalleryID=?
GROUP BY l.LayerID, l.LayerFull, l.LayerLevel,
l.LevelZero, l.LevelOne, l.LevelTwo,
l.LevelThree, l.LevelFour, l.LevelFive
ORDER BY l.LevelZero, l.LevelOne, l.LevelTwo,
l.LevelThree, l.LevelFour, l.LevelFive",
$sparam->{'GAL'}
);
# Initialize
$map = '';
# There is mapping information
if ($mres = $msth->fetchrow_hashref())
{
# Initliaze
my $count;
my $spacer;
my $olayer = $mres->{'LayerLevel'};
# Loop through
do
{
# Level additions
# Change based on up or down
if ($olayer > $mres->{'LayerLevel'})
{
# Drop as far as necessary
$count = $olayer;
# Go down, way down
do
{
# Generate spacer
$spacer = ' ' x ($count-1);
# Move down a level
$map .= $spacer . $gal->{'TagMapStepDown'} . "\n";
# Decrement
$count--;
} while ($count > $mres->{'LayerLevel'});
}
# Moving up
elsif ($olayer < $mres->{'LayerLevel'})
{
# Generate spacer
$spacer = ' ' x ($mres->{'LayerLevel'});
# Move up a level
$map .= $spacer . $gal->{'TagMapStepUp'} . "\n";
}
# General statement
# Spacer for this level
$spacer = ' ' x ($mres->{'LayerLevel'}+1);
# Addition of unit
$map .= $spacer . $tmpl->Pass('TmplMapStep',
MNAME => $mres->{'LayerFull'},
MCOUNT => $mres->{'LayerCount'},
MLINK => $link . '/' . $mres->{'LayerID'} . $inline
);
# Re-assign for next pass
$olayer = $mres->{'LayerLevel'};
} while ($mres = $msth->fetchrow_hashref());
# Close up properly
# Assign
$count = $olayer;
# Look until the end
while ($count > 0)
{
# Generate spacer
$spacer = ' ' x ($count-1);
# Move down a level
$map .= $spacer . $gal->{'TagMapStepDown'} . "\n";
# Decrement
$count--;
}
}
# End query if defined
$msth->finish() if (defined($msth));
# Irrelevant if there are no layers
# Generate template
$works = $tmpl->Pass('TmplMap',
LSTMAP => $map,
MROOT => $gres->{'GalleryName'},
LROOT => $link . $inline
);
# Generate introduction
# Gallery type
if ($gres->{'GalleryType'} eq 'image')
{
# Image galleries
# Paste the introductions first
$intro = $tmpl->Pass('TmplImageIntro',
MDESCR => $gres->{'GalleryDescription'},
MHLIGHT => $gres->{'GalleryHighlight'},
MTHUMB => $gres->{'GalleryThumbnail'},
MGENRE => $genres,
MAUTHOR => $authors,
MRATING => $gres->{'GalleryRating'},
MTITLE => $gres->{'GalleryName'},
MCREATED => $gres->{'GalleryCreated'},
MUPDATED => $gres->{'GalleryUpdated'},
MWATCH => $watch
);
}
# Text based galleries
else
{
# Text galleries
$intro = $tmpl->Pass('TmplTextIntro',
MDESCR => $gres->{'GalleryDescription'},
MGENRE => $genres,
MAUTHOR => $authors,
MRATING => $gres->{'GalleryRating'},
MTITLE => $gres->{'GalleryName'},
MCREATED => $gres->{'GalleryCreated'},
MUPDATED => $gres->{'GalleryUpdated'},
MWATCH => $watch
);
}
# Display final work
# Use all of the toys
$tmpl->Show('TmplListingSec',
MINTRO => $intro,
LSTWORKS => $works,
MNAV => '',
MMAP => ''
);
}
# End query if defined
$gsth->finish() if (defined($gsth));
}
#####################
# Work Search
#
# Allows for searchign through works for specific words and phrases
# reguardless of standard word search of boolean searches.
sub WorkSearch
{
#####################
# Data members
my $database = shift; # Database handler
my $login = shift; # Authenthication handler
my $cgi = shift; # CGI interface
my $param = shift; # Paramater handler
my $tmpl = shift; # Template handler
my $sparam = shift; # Parameter line hash
my $gal = shift; # Gallery hash
my $res; # Work results
my $statement; # Work query statement
my $words; # Words handler
my $length; # Length of string
my $offset; # Where to begin
my $total; # Total amount of entries
my $where; # Where clause
my $url; # Base URL
my $link; # Self-referencing link
my $inline; # Inline parameters
my $descr; # Description
my $layer; # LayerID
my $newness; # Newness factor
my $page; # Page number
my $text; # Text type
my $window; # Window to open to
my $genre; # Genre sort
my $sub; # Sub-types
my $type; # Search type
my $sgnre; # Search genre
my $ssmbt; # Submit
my $stext; # Text handler
my $list; # List of works
my $body; # Search results body
my $search; # Search bar
my $nav; # Navigational bar
my @genre; # Option for genres
my @sub; # Sub genres
my @type; # Gallery Types
#####################
# Data members
# Genres list
# Pull genre lists
$database->GetList(\@type, "SELECT GenreName || '/'
FROM Genre
WHERE GenreSub='' AND GenreType IN ('image','text')");
# Sub-genres
$database->GetList(\@sub, "SELECT GenreSub || '/' || GenreName
FROM Genre
WHERE GenreSub != ''");
# Merge
push(@genre, sort(@type, @sub));
# Generate widgets
# Pupup menu
$sgnre = $cgi->popup_menu('SGNRE', \@genre, $param->{'SGNRE'});
# Submit and submit text field
$ssmbt = $cgi->submit($gal->{'TxtSearch'});
$stext = $cgi->textfield('STEXT', $param->{'STEXT'}, 25, 75);
# Searching template
$search = $tmpl->Pass('TmplSearchForm',
WGENRE => $sgnre,
WSEARCH => $ssmbt,
WTEXT => $stext
);
# Need exists
if (length($param->{'STEXT'}) > 2)
{
# Determine position
$sparam->{'POS'} = ($sparam->{'GAL'} =~ /\d+/)
? $sparam->{'GAL'}
: 1;
# Pull text
$text = $param->{'STEXT'};
# Generate query base
# Create new instance
$words = new Ethereal::Words();
# Determine where statement
$where = $words->Query($text);
# Type and sub-types
($type, $genre) = split(/\//, $param->{'SGNRE'});
# Ensure definition
$genre = ((defined($genre)) && (length($genre) > 2))
? "GenreSub=\'$type\' AND GenreName=\'$genre\'"
: "GenreSub=\'$type\'";
# Fetching of necessary information
# Need weights
$database->Write("SELECT
GalleryID AS GalleryID,
WorkID AS WorkID,
SUM(IndexScore) AS IndexScore,
COUNT(IndexScore) AS IndexMatches
INTO TEMP Weight
FROM Index
WHERE IndexWord IN ($where)
AND EXISTS (SELECT GalleryID
FROM GalleryGenre
WHERE $genre
AND GalleryGenre.GalleryID=Index.GalleryID)
GROUP BY WorkID, GalleryID
LIMIT $gal->{SetMax}");
# Pull total
($total) = $database->DataGet("SELECT COUNT(*) FROM Weight");
# Run based on a temp table
# Prepare query
if ($total > 0)
{
# Navigational
# Self referencing link
$url = $database->{'SYS'}{'LnkIntGallery'}. '/search';
$inline = (defined($param->{'USER'}))
? $param->EmbedInline($param->Flat())
: $param->Crypt($param->Flat());
# Generate template
$nav = Navigation(
$tmpl,
$gal,
$gal->{'SetRetrieve'},
$total,
$sparam->{'POS'},
$url,
$inline
);
# Calculate offset
$offset = ($sparam->{'POS'} - 1) * $gal->{'SetRetrieve'};
# Type and sub-types
($type, $genre) = split(/\//, $param->{'SGNRE'});
# This has enough info for a direct query
if (length($genre) > 2)
{
# Fetch direct match
($type, $sub, $genre) = $database->DataGet("SELECT
GenreType,
GenreSub,
GenreName
FROM Genre
WHERE GenreSub=?
AND GenreName=?", $type, $genre);
}
# Make use of temp table
# Pull full list
$database->Pull(\$statement, "SELECT
wrk.GalleryID AS \"GalleryID\",
wrk.WorkID AS \"WorkID\",
wrk.WorkName AS \"WorkName\",
wrk.WorkLayer AS \"WorkLayer\",
wrk.WorkDescription AS \"WorkDescription\",
wrk.WorkRating AS \"WorkRating\",
wrk.WorkImage AS \"WorkImage\",
wrk.WorkImageSize AS \"WorkImageSize\",
wrk.WorkImageWidth AS \"WorkImageWidth\",
wrk.WorkImageHeight AS \"WorkImageHeight\",
wrk.WorkImageThumbnail AS \"WorkImageThumbnail\",
wrk.WorkText AS \"WorkText\",
getDate(wrk.WorkTimestamp) AS \"WorkTimestamp\",
getNew(wrk.WorkTimestamp) AS \"WorkNewness\"
FROM Work wrk
INNER JOIN Weight wgt
ON wrk.GalleryID=wgt.GalleryID
AND wrk.WorkID=wgt.WorkID
ORDER BY wgt.IndexMatches, wgt.IndexScore
LIMIT $gal->{SetRetrieve} OFFSET $offset");
# Pull all records
if ($res = $statement->fetchrow_hashref())
{
# Adjustment
# Self referencing link
$url = $database->{'SYS'}{'LnkIntGallery'};
# Inline parameters
$inline = (defined($param->{'USER'}))
? $param->EmbedInline(
USER=>$param->{'USER'},
CRYPT=>$param->{'CRYPT'})
: '';
# Loop through
do
{
# Last ditch genre find
($type, $sub, $genre) = $database->DataGet("SELECT
GenreType,
GenreSub,
GenreName
FROM GalleryGenre
WHERE GalleryID=?", $res->{'GalleryID'}
) unless (defined($sub));
# Determine newness
$newness = ($res->{'WorkNewness'} != 0)
? $gal->{'TagNewness'}
: '';
# Handle layers
$layer = (defined($res->{'WorkLayer'}))
? $res->{'WorkLayer'}
: 0;
# Specific link adjustment
$link = $url . '/'
. $type . '/'
. $sub . '/'
. $genre . '/'
. $res->{'GalleryID'} . '/'
. $layer . '/'
. $res->{'WorkID'};
# Window generation
$window = 'WIN' . $res->{'GalleryID'} . 'x' . $res->{'WorkLayer'};
# Display
# Image gallery
if ($res->{'GenreType'} eq 'image')
{
# Display
$list .= $tmpl->Pass('TmplImageList',
MNAME => $res->{'WorkName'},
MDESCR => $res->{'WorkDescription'},
MIMAGE => $res->{'WorkImageThumbnail'},
MLINK => $link . $inline,
MRATING => $res->{'WorkRating'},
MSIZE => $res->{'WorkImageSize'},
MWIDTH => $res->{'WorkImageWidth'},
MHEIGHT => $res->{'WorkImageHeight'},
MTHUMB => $database->{'SYS'}{'SetThumbnail'},
MUPDATED => $res->{'WorkTimestamp'},
MNEWNESS => $newness,
MWINDOW => $window
);
}
# Text gallery
else
{
# Description
$descr = (defined($res->{'WorkDescription'}))
? $res->{'WorkDescription'}
: substr(DBI::neat($res->{'WorkText'}, 252), 1, -1);
# Length
$length = length($res->{'WorkText'});
# Display information
$list .= $tmpl->Pass('TmplTextList',
MNAME => $res->{'WorkName'},
MDESCR => $descr,
MLENGTH => $length,
MLINK => $link .$inline,
MRATING => $res->{'WorkRating'},
MUPDATED => $res->{'WorkTimestamp'},
MNEWNESS => $newness,
MWINDOW => $window
);
}
} while ($res = $statement->fetchrow_hashref());
# Compose body
$body = $tmpl->Pass('TmplSearchBody',
MNAV => $nav,
LSTWORKS => $list
);
}
else
{
# No results
$body = $tmpl->Pass('TmplSearchNotice',
MMESSAGE=>$gal->{'MsgSrchResults'}
);
}
# End execution
$statement->finish();
}
else
{
# Error in execution
$body = $tmpl->Pass('TmplSearchNotice',
MMESSAGE=>$gal->{'MsgSrchResults'}
);
}
# Commit changes
# Ensures that things drop
$database->Write("DROP TABLE Weight");
$database->Commit();
}
# Dsplay to user
# Forms
print $cgi->start_form(-action=>$database->{'SYS'}{'LnkIntGallery'} . '/search');
print $cgi->hidden('SNEW', 'True'), "\n";
print $param->EmbedNormal($param->Flat()) if (defined($param->{'USER'}));
# Display
$tmpl->Show('TmplSearch',
MBODY => $body,
MSEARCH => $search
);
# End form
print $cgi->end_form(), "\n";
}