package Labyrinth::Support; use warnings; use strict; use vars qw($VERSION @ISA %EXPORT_TAGS @EXPORT @EXPORT_OK); $VERSION = '5.24'; =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