# ==================================================================
# Links SQL - enhanced directory management system
#
# Website : http://gossamer-threads.com/
# Support : http://gossamer-threads.com/scripts/support/
# CVS Info : 087,071,085,089,084
# Revision : $Id: Modify.pm,v 1.11 2002/04/04 20:40:32 alex Exp $
#
# Copyright (c) 2001 Gossamer Threads Inc. All Rights Reserved.
# Redistribution in part or in whole strictly prohibited. Please
# see LICENSE file for full details.
# ==================================================================
package Links::User::Modify;
# ==================================================================
use strict;
use Links qw/$DB $IN $USER $CFG/;
use Links::SiteHTML;
sub handle {
# ---------------------------------------------------
# Determine what to do.
#
my $link_id = $IN->param('LinkID');
if ($CFG->{user_required} and ! $USER) {
print $IN->redirect( Links::redirect_login_url ('modify') );
return;
}
# If we have been asked to modify a link, let's do it.
CASE: {
$IN->param('modify') and do { _modify(); last CASE; };
$USER and $IN->param('LinkID') and do { _modify_passed_in(); last CASE; };
$USER and do { _list_owned_links(); last CASE; };
# Otherwise display the modify form.
_modify_form();
}
}
# ==============================================================
sub _modify {
# --------------------------------------------------------
# Modifies a link.
#
my $results = GT::Plugins->dispatch ($CFG->{admin_root_path} . '/Plugins', 'user_modify_link', \&modify_link, {});
if (defined $results->{error}) {
print $IN->header();
print Links::SiteHTML::display ('modify', $results);
}
else {
print $IN->header();
print Links::SiteHTML::display ('modify_success', $results);
}
}
sub _modify_passed_in {
# --------------------------------------------------------
# Display link that was passed in.
#
my ($name, $category);
my $lid = $IN->param('LinkID');
my $link_db = $DB->table('Links');
my $sth = $link_db->select ( { ID => $lid, LinkOwner => $USER->{Username} });
if ($sth->rows) {
my $link = $sth->fetchrow_hashref;
my $catlink_db = $DB->table('CatLinks');
$sth = $catlink_db->select ( { LinkID => $link->{ID} }, ['CategoryID'] );
my @catid = $sth->fetchall_list;
$IN->param ('CatLinks.CategoryID', \@catid);
$link->{Contact_Name} ||= $USER->{Name} || $USER->{Username};
$link->{Contact_Email} ||= $USER->{Email};
my $category = _category_list();
$link->{Category} = $category;
print $IN->header();
print Links::SiteHTML::display('modify', $link);
}
else {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('MODIFY_NOTOWNER'), LinkID => $lid });
}
}
sub _list_owned_links {
# --------------------------------------------------------
# Display a list of links the user owns.
#
my $link_db = $DB->table('Links');
my $mh = $IN->param('mh') || 25;
my $nh = $IN->param('nh') || 1;
$link_db->select_options ("LIMIT " . (($nh-1)*$mh) . ",$mh");
my $sth = $link_db->select ( { LinkOwner => $USER->{Username}, isValidated => 'Yes' });
my $total = $link_db->hits;
if (! $sth->rows) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('MODIFY_NOLINKS') });
return;
}
my $toolbar;
my @links;
while (my $hash = $sth->fetchrow_hashref) {
push @links, $hash;
}
if ($total > $mh) {
my $url = $CFG->{db_cgi_url} . "/" . $IN->url( query_string => 1, absolute => 0 );
$toolbar = $DB->html(['Links'], $IN)->toolbar ($nh, $mh, $total, $url);
}
print $IN->header();
print Links::SiteHTML::display ('modify_select', { link_results_loop => \@links, total => $total, next => $toolbar });
}
sub _modify_form {
# --------------------------------------------------------
# Just display the regular form.
#
my $id = $IN->param('ID'); # Category ID.
if (! $id and ! $CFG->{db_gen_category_list}) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('MODIFY_SELCAT') });
}
else {
my $category = _category_list();
print $IN->header();
if (! $category) {
print Links::SiteHTML::display('error', { error => Links::language('ADD_INVALIDCAT', $IN->param('ID')) });
}
else {
print Links::SiteHTML::display('modify', { Category => $category });
}
}
}
sub modify_link {
# --------------------------------------------------------
# Change the requested link.
#
my $category = _category_list();
my $args = $IN->get_hash();
my $db = $DB->table ('Links');
my $cols = $db->cols;
my ($column, $value);
foreach my $col (keys %$cols) {
if (exists $args->{'Current_' . $col}) {
$column = $col;
$value = $args->{'Current_' . $col};
last;
}
}
my $lid = $args->{'LinkID'};
if (! ($value or $lid)) {
return { error => Links::language('MODIFY_NOURL'), Category => $category, LinkID => $lid };
}
# Find the URL requested.
my ($link, $sth);
if ($USER and $lid) {
$sth = $db->select ( { ID => $lid, LinkOwner => $USER->{Username} });
$sth->rows or return { error => Links::language('MODIFY_BADURL', $lid), Category => $category, LinkID => $lid };
}
else {
$sth = $db->select ( { $column => $value } );
$sth->rows or return { error => Links::language('MODIFY_BADURL', $value), Category => $category, LinkID => $lid };
}
$link = $sth->fetchrow_hashref;
# Preserve any system fields.
my $new = {};
my %cols = $db->cols;
foreach my $key (keys %cols) {
(exists $CFG->{add_system_fields}->{$key}) ?
($new->{$key} = $link->{$key}) :
($new->{$key} = defined $args->{$key} ? $args->{$key} : $link->{$key});
}
# Make sure we have the ID set properly.
$new->{ID} = $link->{ID};
$new->{LinkOwner} = $link->{LinkOwner};
# Set the dates properly.
Links::init_date();
$new->{'Add_Date'} = $link->{'Add_Date'};
$new->{'Mod_Date'} = GT::Date::date_get();
# Setup the language for GT::SQL.
local $GT::SQL::ERRORS->{ILLEGALVAL} = Links::language('ADD_ILLEGALVAL');
local $GT::SQL::ERRORS->{UNIQUE} = Links::language('ADD_UNIQUE');
local $GT::SQL::ERRORS->{NOTNULL} = Links::language('ADD_NOTNULL');
local $Links::Link::ERRORS->{NOCATEGORY} = Links::language('MODIFY_NOCATEGORY');
$Links::Link::ERRORS ||= {}; # silence -w
# Make sure not nulls are not null (check update doesn't handle this anymore).
my %not_null_cols = $db->not_null;
foreach my $col (keys %not_null_cols) {
if ($not_null_cols{$col}) {
unless (defined $new->{$col} and ($new->{$col} ne '')) {
return { error => Links::language('ADD_NOTNULL', $col), Category => $category, LinkID => $lid };
}
}
}
# Check that it's valid:
$db->_check_update ($new, { ID => $new->{ID} })
or return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
# Make sure the category id's are valid.
$IN->param('CatLinks.CategoryID')
or return { error => Links::language('MODIFY_NOCATEGORY'), Category => $category, LinkID => $lid };
# Set the ID's and Category ID's and remove timestamp field.
my @c_ids = $IN->param('CatLinks.CategoryID');
$new->{'CatLinks.CategoryID'} = \@c_ids;
$new->{'CatLinks.CategoryID'} = $db->clean_category_ids ( $new->{'CatLinks.CategoryID'} )
or return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
# Backward compatibility..
my $name = $args->{'Contact_Name'} || $args->{'Contact Name'} || ($USER ? $USER->{Name} : '');
my $email = $args->{'Contact_Email'} || $args->{'Contact Email'} || ($USER ? $USER->{Email} : '');
$new->{'Contact_Name'} = $name;
$new->{'Contact_Email'} = $email;
# Make sure a contact name and email were entered and are valid.
my $user_db = $DB->table ('Users');
my $user_cols = $user_db->cols;
$name or $db->error ('NOTNULL', 'WARN', $user_cols->{Name}->{form_display} || 'Contact Name');
$email or $db->error ('NOTNULL', 'WARN', $user_cols->{Email}->{form_display} || 'Contact Email');
$email =~ /^.+\@.+\..+$/ or $db->error ('ILLEGALVAL', 'WARN', $user_cols->{Email}->{form_display} || 'Contact Email', $email);
if ($db->error) {
return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
}
# Remove the timestamp.
delete $new->{Timestmp};
my $orig_cats = $db->get_categories ($new->{ID});
my $new_cats;
my $save = {};
foreach my $k (keys %$new) { $save->{$k} = $new->{$k}; }
foreach my $k (keys %$args) { $save->{$k} = $args->{$k} unless (exists $save->{$k}); }
# Add the link either directly in, or into the change request table.
if ($USER and $CFG->{user_direct_mod}) {
if ($USER->{Status} ne 'Administrator') {
if ($link->{LinkOwner} ne $USER->{Username}) {
return { error => Links::language('MODIFY_NOTOWNER'), Category => $category, LinkID => $lid };
}
}
if ( my %fcols = $db->_file_cols() ) {
foreach my $col_name ( keys %fcols ) {
if ( $args->{$col_name."_del"} ) { $save->{$col_name."_del"} = ''; next };
my $fh = $args->{$col_name};
ref $fh or ( $save->{$col_name} = '', next );
$save->{$col_name} = $fh;
}
}
my $res = $db->modify ($new) or return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
$new_cats = $db->get_categories ($new->{ID});
}
else {
require GT::Dumper;
my $chg_db = $DB->table ('Changes');
# ... handle files
if ( my %fcols = $db->_file_cols() ) {
foreach my $col_name ( keys %fcols ) {
if ( $args->{$col_name."_del"} ) { $save->{$col_name."_del"} = ''; next };
my $fh = $args->{$col_name};
ref $fh or ( $save->{$col_name} = '', next );
my $fname = GT::CGI->escape(get_filename("$fh"));
my $fpath = "$CFG->{admin_root_path}/tmp/$save->{ID}-$fname";
open F, ">$fpath";
binmode F; binmode $fh;
my $buf;
while( read $fh, $buf, 4096 ){ print F $buf; };
close F;
$save->{$col_name} = $fpath;
$save->{$col_name."_filename"} = get_filename("$fh");
}
};
my $sth = $chg_db->select ( { LinkID => $new->{ID} }, ['LinkID']);
if ($sth->rows) {
my $href = $chg_db->get({ LinkID => $new->{ID} }) || {};
$href = eval $href->{ChgRequest};
my %fcols = $db->_file_cols();
foreach ( keys %fcols ) {
my $fpath = $href->{$_} or next;
( $fpath ne $save->{$_} ) or next;
( $fpath !~ /\.\./) or next;
( $fpath =~ /^[\w\\\/\-\.%]+$/) or next;
( -e $fpath ) or next;
( $fpath =~ m,^$CFG->{admin_root_path}/tmp/,) or next;
unlink $fpath;
}
$chg_db->update ( { LinkID => $new->{ID}, Username => $new->{LinkOwner}, ChgRequest => GT::Dumper->dump ( { data => $save, var => '' }) }, { LinkID => $new->{ID} } )
or return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
}
else {
$chg_db->insert ( { LinkID => $new->{ID}, Username => $new->{LinkOwner}, ChgRequest => GT::Dumper->dump ( { data => $save, var => '' }) })
or return { error => $GT::SQL::error, Category => $category, LinkID => $lid };
}
my $cdb = $DB->table ('Category');
foreach my $id (@c_ids) {
my $cat = $cdb->get ($id, 'HASH', ['Full_Name']);
$new_cats->{$id} = $cat->{Full_Name};
}
}
# Now email the site admin.
if ($CFG->{admin_email_mod}) {
send_email ($link, $new, $orig_cats, $new_cats);
}
$save->{Category} = join ("\n", values %$new_cats);
# All done!
return $save;
}
sub send_email {
# --------------------------------------------------------
# Sends an email to the admin, letting him know that there is
# a new link waiting to be validated.
#
my ($original, $new, $orig_cats, $new_cats) = @_;
my ($to, $from, $subject, $msg, $text, $mailer, $c_origname, $c_newname, $host, $refer);
# Check to make sure that there is an admin email address defined.
$to = $CFG->{db_admin_email} || return;
$from = $new->{'Contact_Email'};
$subject = "Modification to Database: $new->{Title}";
$c_origname = join ("\n", values %$orig_cats);
$c_newname = join ("\n", values %$new_cats);
$host = $ENV{REMOTE_HOST} ? "$ENV{REMOTE_HOST} ($ENV{REMOTE_ADDR})" : $ENV{REMOTE_ADDR} ? $ENV{REMOTE_ADDR} : 'none';
$refer = $ENV{HTTP_REFERER} ? $ENV{HTTP_REFERER} : 'none';
my %tags;
foreach my $key (keys %$original) {
$tags{"Original_" . $key} = $original->{$key};
}
foreach my $key (keys %$new) {
$tags{"New_" . $key} = $new->{$key};
}
$tags{"Original_Category"} = $c_origname;
$tags{"New_Category"} = $c_newname;
$tags{"Host"} = $host;
$tags{"Referer"} = $refer;
my $cfg = Links::Config::load_vars();
$msg = GT::Template->parse ( 'email-mod.txt', { %tags, %$cfg }, { compress => 0, root => $CFG->{admin_root_path} . '/templates/admin' } );
# Then mail it away!
require GT::Mail;
$GT::Mail::error ||= '';
GT::Mail->send (
smtp => $CFG->{db_smtp_server},
sendmail => $CFG->{db_mail_path},
from => $from,
subject => $subject,
to => $to,
msg => $msg,
debug => $Links::DEBUG
) or die "Unable to send message: $GT::Mail::error";
}
sub _category_list {
# -------------------------------------------------------------------
# Return a list of all the categories.
#
my $category;
if ($CFG->{db_gen_category_list}) {
my $db = $DB->table('Links');
my $html = $DB->html($db, $IN);
my @ids = $IN->param('CatLinks.CategoryID');
@ids or push @ids, $IN->param('ID');
$category = $html->get_all_categories(\@ids, 'CatLinks.CategoryID', 5);
}
else {
my $db = $DB->table('Category');
my @ids = $IN->param('CatLinks.CategoryID');
@ids or push @ids, $IN->param('ID');
$db->select_options ('ORDER by Full_Name');
my $sth = $db->select ( { ID => \@ids }, ['ID','Full_Name'] );
my $names = $sth->fetchall_hashref();
for (@$names) {
$category .= qq|$_->{Full_Name}
|;
}
}
return $category;
}
sub get_filename {
# -------------------------------------------------------------------
my $fpath = shift;
my @path = split /[\\\/]/, $fpath;
return pop @path;
}
1;