package Labyrinth::Support;
use warnings;
use strict;
use vars qw($VERSION @ISA %EXPORT_TAGS @EXPORT @EXPORT_OK);
$VERSION = '5.29';
=head1 NAME
Labyrinth::Support - Common Function Library for Labyrinth.
=head1 SYNOPSIS
use Labyrinth::Support;
=head1 DESCRIPTION
The functions contain herein are commonly used throughout Labyrinth and
plugins.
=head1 EXPORT
AlignName
AlignClass
AlignSelect
PublishState
PublishSelect
PublishAction
FieldCheck
ParamCheck
AuthorCheck
MasterCheck
AccessName
AccessID
AccessUser
AccessGroup
AccessSelect
AccessAllFolders
AccessAllAreas
RealmCheck
RealmSelect
RealmName
RealmID
ProfileSelect
FolderName
FolderID
FolderSelect
AreaSelect
=cut
# -------------------------------------
# Export Details
require Exporter;
@ISA = qw(Exporter);
%EXPORT_TAGS = (
'all' => [ qw(
AlignName AlignClass AlignSelect
PublishState PublishSelect PublishAction
FieldCheck ParamCheck AuthorCheck MasterCheck
AccessName AccessID AccessUser AccessGroup AccessSelect
AccessAllFolders AccessAllAreas
RealmCheck RealmSelect RealmName RealmID
ProfileSelect FolderName FolderID FolderSelect AreaSelect
) ]
);
@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
@EXPORT = ( @{ $EXPORT_TAGS{'all'} } );
# -------------------------------------
# Library Modules
use Time::Local;
use Labyrinth::Audit;
use Labyrinth::Globals;
use Labyrinth::Groups;
use Labyrinth::MLUtils;
use Labyrinth::Session;
use Labyrinth::Writer;
use Labyrinth::Variables;
# -------------------------------------
# The Subs
=head1 FUNCTIONS
=over 4
=item PublishState
Returns the name of the current publish state, given the numeric state.
=item PublishSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available publishing states.
=item PublishAction
Provides a dropdown selection box, as a XHTML code snippet, of the currently
accessible publishing states.
=cut
my %publishstates = (
1 => {Action => 'Draft', State => 'Draft' },
2 => {Action => 'Submit', State => 'Submitted' },
3 => {Action => 'Publish', State => 'Published' },
4 => {Action => 'Archive', State => 'Archived' },
);
my @states = map {{'id'=>$_,'value'=> $publishstates{$_}->{State}}} sort keys %publishstates;
sub PublishState {
my $state = shift;
return '' unless($state);
return $publishstates{$state}->{State};
}
sub PublishSelect {
my ($opt,$blank) = @_;
my @list = @states;
unshift @list, {id=>0,value=>'Select Status'} if(defined $blank && $blank == 1);
DropDownRows($opt,'publish','id','value',@list);
}
sub PublishAction {
my $opt = shift || 1;
my $ack = shift || -1;
my $html = qq{<select id="publish" name="publish">};
foreach (sort keys %publishstates) {
unless($ack == -1) {
next if(!$ack && $_ != $opt);
next if($_ < $opt || $_ > $opt+1);
}
$html .= "<option value='$_'";
$html .= ' selected="selected"' if($opt == $_);
$html .= ">$publishstates{$_}->{Action}</option>";
}
$html .= "</select>";
return $html;
}
my %alignments = (
0 => { name => 'none', class => 'nail' },
1 => { name => 'left', class => 'left' },
2 => { name => 'centre', class => 'centre' },
3 => { name => 'right', class => 'right' },
4 => { name => 'left (no wrap)', class => 'lnowrap' },
5 => { name => 'right (no wrap)', class => 'rnowrap' },
);
my @alignments = map {{'id'=>$_,'value'=> $alignments{$_}->{name}}} sort keys %alignments;
=item AlignName
Returns the name of the given alignment type, defaults to 'none'.
=item AlignClass
Returns the class of the given alignment type, defaults to 'nail'.
=item AlignSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available alignment states.
=cut
sub AlignName {
my $opt = shift || 1;
return $alignments{$opt}->{name};
}
sub AlignClass {
my $opt = shift || 1;
return $alignments{$opt}->{class};
}
sub AlignSelect {
my $opt = shift || 0;
my $num = shift || 0;
DropDownRows($opt,"ALIGN$num",'id','value',@alignments);
}
=item AuthorCheck
Checks whether the current user is the author of the data requested, or has
permissions to allow them to access the data. If not sets the BADACCESS error
code, otherwise retrieves the data.
=cut
sub AuthorCheck {
my ($key,$id,$permission) = @_;
return 1 unless($cgiparams{$id}); # if the id key doesn't exist, this is likely to be a new entry
$permission = ADMIN unless(defined $permission);
my @rows = $dbi->GetQuery('hash',$key,$cgiparams{$id});
return 0 unless(@rows);
$tvars{data}{$_} = $rows[0]->{$_} for(keys %{$rows[0]});
return 1 if(Authorised($permission));
return 1 if($rows[0]->{userid} && $rows[0]->{userid} == $tvars{'loginid'});
$tvars{errcode} = 'BADACCESS';
return 0;
}
=item MasterCheck
Ensure only a Master user can access a Master user details.
=cut
sub MasterCheck {
return 1 if( !$cgiparams{userid} || ! Authorised(MASTER,$cgiparams{userid}) );
return 1 if( Authorised(MASTER,$cgiparams{userid}) && Authorised(MASTER,$tvars{'loginid'}) );
$tvars{errcode} = 'BADACCESS';
return 0;
}
=item FieldCheck(\@allfields,\@mandatory)
Stores all the input data listed in @allfields, then checks that all the fields
listed in @mandatory are provided. Any errors found during parameter parsing
both for missing mandatory fields and via Data::FormValidator are then flagged
and the error code set.
=item ParamCheck(\%fields)
Cleans data inputs, then stores all the input data fields in $tvars{data}. All
mandatory fields are validated to ensure each has a value. Any errors found
during parameter parsing both for missing mandatory fields and via
Data::FormValidator are then flagged and the error code set.
The fields hash contains a list of fields, with the keys 'type' and 'html'.
'type' indicates whether the field is mandatory (1) or optional (0). 'html'
indicates the level of cleaning required:
my %fields = (
linkid => { type => 0, html => 0 },
catid => { type => 0, html => 0 },
href => { type => 1, html => 1 },
title => { type => 1, html => 3 },
body => { type => 0, html => 2 },
);
# type: 0 = optional, 1 = mandatory
# html: 0 = none, 1 = text, 2 = textarea, 3 = no links
'0' should only be used if previous parameter validation via
Data::FormValidator has already ensured that only legal characters are used.
'1' removes all HTML tags.
'2' removes disallowed HTML tags and cleans up many tags and whitespace.
'3' removes anything that looks like a link or script tag, with the aim of
preventing a XSS attack.
=cut
sub FieldCheck {
my ($allfields,$mandatory) = @_;
# store base list for re-edit page
foreach (@$allfields) {
# automatically turn arrays into strings, in case someone is trying
# to subvert the data input process. known arrays are correctly stored
# appropriately elsewhere.
$tvars{data}->{$_} = join("|",CGIArray($_));
}
# check for mandatory fields
my $errors = 0;
foreach (@$mandatory) {
if(defined $cgiparams{$_} && exists $cgiparams{$_} && $cgiparams{$_}) {
# nothing
} else {
LogDebug("FieldCheck: mandatory missing - [$_]");
$tvars{data}->{$_.'_err'} = ErrorSymbol();
$errors++;
$tvars{errcode} = 'ERROR';
}
}
# check for invalid fields
for my $z (keys %cgiparams) {
next unless($z =~ /err_(.*)/);
my $x = $1;
$tvars{data}->{$x . '_err'} = ErrorSymbol();
$errors++;
$tvars{errcode} = 'ERROR';
}
return($errors);
}
sub ParamCheck {
my ($fields) = @_;
my $errors = 0;
for my $key (keys %$fields) {
# clean up cgi parameters
if($fields->{$key}{html} == 1) { $cgiparams{$key} = CleanHTML($cgiparams{$key}) }
elsif($fields->{$key}{html} == 2) { $cgiparams{$key} = CleanTags($cgiparams{$key}) }
elsif($fields->{$key}{html} == 3) { $cgiparams{$key} = CleanLink($cgiparams{$key}) }
# store field
# automatically turn arrays into strings, in case someone is trying
# to subvert the data input process. known arrays are correctly stored
# appropriately elsewhere.
$tvars{data}->{$_} = join("|",CGIArray($_));
# skip checks if optional field
next unless($fields->{$key}{type});
# mandatory fields must contain values
next if(defined $cgiparams{$_} && exists $cgiparams{$_} && $cgiparams{$_});
# if we get here, record missing field
LogDebug("FieldCheck: mandatory missing - [$_]");
$tvars{data}->{$_.'_err'} = ErrorSymbol();
$errors++;
$tvars{errcode} = 'ERROR';
}
# check for invalid fields
for my $z (keys %cgiparams) {
next unless($z =~ /err_(.*)/);
my $x = $1;
$tvars{data}->{$x . '_err'} = ErrorSymbol();
$errors++;
$tvars{errcode} = 'ERROR';
}
return($errors);
}
=item AccessName
Returns the access permission name, given the access id.
=item AccessID
Returns the access id, given the access permission name.
=item AccessUser
Returns whether the current user has access at the given level of permissions.
Default permission level is ADMIN. Returns 1 if permission is granted, 0
otherwise.
=item AccessGroup
Returns whether the current user has access to the given group. Returns 1 if
yes, 0 otherwise.
=item AccessSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available access states.
=item AccessAllFolders
Return list of folders current user has access to.
=item AccessAllAreas
Return list of areas current user has access to.
=cut
sub AccessName {
my $value = shift;
LoadAccess();
return $settings{access}{ids}{$value};
}
sub AccessID {
my $value = shift;
LoadAccess();
return $settings{access}{names}{$value};
}
sub AccessUser {
my $permission = shift;
$permission = ADMIN unless(defined $permission);
return 1 if(Authorised($permission));
$tvars{errcode} = 'BADACCESS';
return 0;
}
sub AccessGroup {
my %hash = @_;
my $groupid = $hash{ID} || GetGroupID($hash{NAME});
return 0 unless($groupid); # this is not bad access, the group may have been deleted
return 1 if UserInGroup($groupid);
$tvars{errcode} = 'BADACCESS';
return 0;
}
sub AccessSelect {
my $opt = shift || 0;
my $name = shift || 'accessid';
my $max = Authorised(MASTER) ? MASTER : ADMIN;
my @rows = $dbi->GetQuery('hash','AllAccess',$max);
DropDownRows($opt,$name,'accessid','accessname',@rows);
}
sub AccessAllFolders {
my $userid = shift || $tvars{loginid};
my $access = shift || PUBLISHER;
my $groups = getusergroups($userid);
my @rows = $dbi->GetQuery('array','GetFolderAccess',
{groups=>$groups,userid=>$userid,access=>$access});
my @folders = map {$_->[0]} @rows;
return join(',',@folders);
}
sub AccessAllAreas {
my @rows = $dbi->GetQuery('array','AllAreas');
my @areas = map {"'$_->[0]'"} @rows;
return join(',',@areas);
}
=item RealmCheck
Checks whether the given realm is known within the system.
=item RealmSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available realms.
=item RealmName
Returns the name of a realm, given a realm id.
=item RealmID
Returns the id of a realm, given a realm name.
=cut
sub RealmCheck {
while(@_) {
my $realm = shift;
return 1 if($realm eq $tvars{realm});
}
$tvars{errcode} = 'BADACCESS';
return 0; # failed
}
sub RealmSelect {
my $opt = shift;
my @rows = $dbi->GetQuery('hash','AllRealms');
DropDownRows($opt,'realmid','realmid','name',@rows);
}
sub RealmName {
my $id = shift;
my @rows = $dbi->GetQuery('hash','GetRealmByID',$id);
return $rows[0]->{realm};
}
sub RealmID {
my $name = shift;
my @rows = $dbi->GetQuery('hash','GetRealmByName',$name);
return $rows[0]->{realmid};
}
=item ProfileSelect
Returns a dropdown list for the current list of profiles.
=item FolderID
Returns the folder id, given the folder name.
=item FolderName
Returns the name of a folder, given a folder id.
=item FolderSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available folders.
=cut
sub ProfileSelect {
my $opt = shift || 0;
my $name = shift || 'profile';
LoadProfiles();
my @rows = map { { profile => $_ } } sort grep {$_ ne $settings{profiles}{default} } keys %{$settings{profiles}{profiles}};
unshift @rows, { profile => $settings{profiles}{default} } if($settings{profiles}{default});
unshift @rows, { profile => 'Select Profile' };
DropDownRows($opt,$name,'profile','profile',@rows);
}
sub FolderID {
my $opt = shift || return;
my @rows = $dbi->GetQuery('hash','GetFolderByPath',$opt);
return @rows ? $rows[0]->{folderid} : undef;
}
sub FolderName {
my $opt = shift || return;
my @rows = $dbi->GetQuery('hash','GetFolder',$opt);
return @rows ? $rows[0]->{foldername} : undef;
}
sub FolderSelect {
my $opt = shift || 0;
my $name = shift || 'folderid';
my @rows = $dbi->GetQuery('hash','AllFolders');
DropDownRows($opt,$name,'folderid','foldername',@rows);
}
=item AreaSelect
Provides a dropdown selection box, as a XHTML code snippet, of the currently
available areas.
=cut
sub AreaSelect {
my $opt = shift;
my @rows = $dbi->GetQuery('hash','AllAreas');
DropDownRows($opt,'area','areaid','title',@rows);
}
1;
__END__
=back
=head1 SEE ALSO
Time::Local
Labyrinth
=head1 AUTHOR
Barbie, <barbie@missbarbell.co.uk> for
Miss Barbell Productions, L<http://www.missbarbell.co.uk/>
=head1 COPYRIGHT & LICENSE
Copyright (C) 2002-2014 Barbie for Miss Barbell Productions
All Rights Reserved.
This module is free software; you can redistribute it and/or
modify it under the Artistic License 2.0.
=cut