First pass at adding key files
This commit is contained in:
		
							
								
								
									
										183
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/BKS2.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/BKS2.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#   Website  : http://gossamer-threads.com/
 | 
			
		||||
#   Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#   CVS Info : 087,071,086,086,085      
 | 
			
		||||
#   Revision : $Id: BKS2.pm,v 1.14 2005/03/05 01:46:07 brewt 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::Import::BKS2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_) if ref $Critical_Code eq 'CODE';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_) if ref $Warning_Code eq 'CODE';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $prefix = $DB->prefix || "";
 | 
			
		||||
 | 
			
		||||
    my $odbc = 0;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
        if ($table->{connect}->{driver} eq 'ODBC') {
 | 
			
		||||
            $odbc = 1;
 | 
			
		||||
            $e_dbh->{LongReadLen} = 1000000;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $delimiter;
 | 
			
		||||
 | 
			
		||||
    local (*IMPORT_FH);
 | 
			
		||||
    local $/ = "\0"; # "Lines" are actually delimited by \0 (hex & ascii 0)
 | 
			
		||||
 | 
			
		||||
    import_print "Verifying table headers ...\n";
 | 
			
		||||
 | 
			
		||||
    my $all_problems = "";
 | 
			
		||||
    open IMPORT_FH, "<$$opt{source}" or critical "Unable to open $$opt{source}: $!";
 | 
			
		||||
    binmode IMPORT_FH; # Don't want to worry about windows line feeds!
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        last if substr($_,0,2) eq '\\\\';
 | 
			
		||||
    } # Eat up until a \\
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        chomp;
 | 
			
		||||
        my $table = $_;
 | 
			
		||||
        import_print "\tChecking $table\n";
 | 
			
		||||
        my $has_problems = 0;
 | 
			
		||||
        TABLE: while (<IMPORT_FH>) {
 | 
			
		||||
            chomp;
 | 
			
		||||
            my $header = $_;
 | 
			
		||||
            my $delimiter = substr($header,0,1);
 | 
			
		||||
            substr($header,0,1) = '';
 | 
			
		||||
            my @cols = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $header, -1;
 | 
			
		||||
            my %cols = $DB->table($table)->cols;
 | 
			
		||||
            my $problem = "";
 | 
			
		||||
            for (grep !$cols{$_}, @cols) {
 | 
			
		||||
                $problem .= ($problem ? ", " : "") . $_;
 | 
			
		||||
            }
 | 
			
		||||
            if ($problem) {
 | 
			
		||||
                my $plural = $problem =~ /, /;
 | 
			
		||||
                $all_problems .= "\nThe following column".($plural?"s":"")." in the $table table ($$opt{source}) ".($plural?"are":"is")." NOT in the Gossamer Links database: $problem. ".($plural?"They":"It")." will have to be created prior to performing this import.";
 | 
			
		||||
                $has_problems++;
 | 
			
		||||
            }
 | 
			
		||||
            while (<IMPORT_FH>) {
 | 
			
		||||
                last TABLE if substr($_,0,2) eq '\\\\';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    close IMPORT_FH;
 | 
			
		||||
    critical $all_problems if $all_problems;
 | 
			
		||||
 | 
			
		||||
    import_print "All tables verified successfully\n\n\n";
 | 
			
		||||
    
 | 
			
		||||
    open IMPORT_FH, "<$$opt{source}" or critical "Unable to open $$opt{source}: $!";
 | 
			
		||||
    binmode IMPORT_FH; # Don't want to worry about windows line feeds!
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        last if substr($_,0,2) eq '\\\\';
 | 
			
		||||
    } # Eat up until \\
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        chomp;
 | 
			
		||||
        my $table = $_;
 | 
			
		||||
        $e_dbh->do("DELETE FROM $prefix$_");
 | 
			
		||||
        import_print "Importing $prefix$table ... (starting at line ".($.+2)." of $$opt{source})\n";
 | 
			
		||||
        my $imported = 0;
 | 
			
		||||
        TABLE: while (<IMPORT_FH>) {
 | 
			
		||||
            chomp;
 | 
			
		||||
            my $header = $_;
 | 
			
		||||
            my $delimiter = substr($header,0,1);
 | 
			
		||||
            substr($header,0,1) = '';
 | 
			
		||||
            my @cols = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $header, -1;
 | 
			
		||||
 | 
			
		||||
# If this is an ODBC db, we need to turn identity insert on.
 | 
			
		||||
            my $insert = "INSERT INTO $prefix$table (" . join(",", @cols) . ") VALUES (" . join(",",("?") x @cols) . ")";
 | 
			
		||||
            if ($odbc) {
 | 
			
		||||
                if ($DB->table($table)->ai) {
 | 
			
		||||
                    $insert = "SET IDENTITY_INSERT $prefix$table ON; $insert";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            my $sth = $e_dbh->prepare($insert) or critical "Unable to prepare query `$insert': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
            import_print "\tStarting import to table $prefix$table ...\n";
 | 
			
		||||
            while (<IMPORT_FH>) {
 | 
			
		||||
                last TABLE if substr($_,0,2) eq '\\\\';
 | 
			
		||||
                chomp;
 | 
			
		||||
                my @data = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $_, -1;
 | 
			
		||||
                $sth->execute(@data) or warning "\tUnable to import `$_' (line $. of $$opt{source}): ".$sth->errstr;
 | 
			
		||||
                import_print "\t$imported imported ...\n" unless ++$imported % 500;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "\t$imported records imported to $prefix$table.\n",
 | 
			
		||||
              "All records have been imported to $prefix$table.\n\n";
 | 
			
		||||
    }
 | 
			
		||||
    import_print "All tables contained in $$opt{source} have been imported.\n\nNOTE: You must run Repair Tables and Rebuild Search after performing an import!\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Takes two parameters: The field to escape, and the delimiter. It will return
 | 
			
		||||
# the field unescaped.
 | 
			
		||||
sub BK_unescape ($$) {
 | 
			
		||||
    my $field = shift;
 | 
			
		||||
    my $delimiter = shift;
 | 
			
		||||
    $delimiter = "" unless defined $delimiter;
 | 
			
		||||
    critical "Bad delimiter `$delimiter'" unless length $delimiter == 1 and $delimiter ne '\\';
 | 
			
		||||
    critical "An escaped field cannot be undefined. You have data errors!" unless defined $field;
 | 
			
		||||
    return undef if $field eq 'NULL';
 | 
			
		||||
    my $escape_chr = '\\';
 | 
			
		||||
    $field =~ s/\Q$escape_chr\E([0-9A-Fa-f]{2})/chr hex $1/ge;
 | 
			
		||||
    $field;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
2;
 | 
			
		||||
@@ -0,0 +1,189 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#   Website  : http://gossamer-threads.com/
 | 
			
		||||
#   Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#   CVS Info : 087,071,086,086,085      
 | 
			
		||||
#   Revision : $Id: BKS2.pm,v 1.14 2005/03/05 01:46:07 brewt 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::Import::BKS2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_) if ref $Critical_Code eq 'CODE';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_) if ref $Warning_Code eq 'CODE';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $prefix = $DB->prefix || "";
 | 
			
		||||
 | 
			
		||||
    my $odbc = 0;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
        if ($table->{connect}->{driver} eq 'ODBC') {
 | 
			
		||||
            $odbc = 1;
 | 
			
		||||
            $e_dbh->{LongReadLen} = 1000000;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $delimiter;
 | 
			
		||||
 | 
			
		||||
    local (*IMPORT_FH);
 | 
			
		||||
    local $/ = "\0"; # "Lines" are actually delimited by \0 (hex & ascii 0)
 | 
			
		||||
 | 
			
		||||
    import_print "Verifying table headers ...\n";
 | 
			
		||||
 | 
			
		||||
    my $all_problems = "";
 | 
			
		||||
    open IMPORT_FH, "<$$opt{source}" or critical "Unable to open $$opt{source}: $!";
 | 
			
		||||
    binmode IMPORT_FH; # Don't want to worry about windows line feeds!
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        last if substr($_,0,2) eq '\\\\';
 | 
			
		||||
    } # Eat up until a \\
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        chomp;
 | 
			
		||||
        my $table = $_;
 | 
			
		||||
        import_print "\tChecking $table\n";
 | 
			
		||||
        my $has_problems = 0;
 | 
			
		||||
        TABLE: while (<IMPORT_FH>) {
 | 
			
		||||
            chomp;
 | 
			
		||||
            my $header = $_;
 | 
			
		||||
            my $delimiter = substr($header,0,1);
 | 
			
		||||
            substr($header,0,1) = '';
 | 
			
		||||
            my @cols = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $header, -1;
 | 
			
		||||
            my %cols = $DB->table($table)->cols;
 | 
			
		||||
            my $problem = "";
 | 
			
		||||
            for (grep !$cols{$_}, @cols) {
 | 
			
		||||
                $problem .= ($problem ? ", " : "") . $_;
 | 
			
		||||
            }
 | 
			
		||||
            if ($problem) {
 | 
			
		||||
                my $plural = $problem =~ /, /;
 | 
			
		||||
                $all_problems .= "\nThe following column".($plural?"s":"")." in the $table table ($$opt{source}) ".($plural?"are":"is")." NOT in the Gossamer Links database: $problem. ".($plural?"They":"It")." will have to be created prior to performing this import.";
 | 
			
		||||
                $has_problems++;
 | 
			
		||||
            }
 | 
			
		||||
            while (<IMPORT_FH>) {
 | 
			
		||||
                last TABLE if substr($_,0,2) eq '\\\\';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    close IMPORT_FH;
 | 
			
		||||
    critical $all_problems if $all_problems;
 | 
			
		||||
 | 
			
		||||
    import_print "All tables verified successfully\n\n\n";
 | 
			
		||||
    
 | 
			
		||||
    open IMPORT_FH, "<$$opt{source}" or critical "Unable to open $$opt{source}: $!";
 | 
			
		||||
    binmode IMPORT_FH; # Don't want to worry about windows line feeds!
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        last if substr($_,0,2) eq '\\\\';
 | 
			
		||||
    } # Eat up until \\
 | 
			
		||||
    while (<IMPORT_FH>) {
 | 
			
		||||
        chomp;
 | 
			
		||||
        my $table = $_;
 | 
			
		||||
        #$e_dbh->do("DELETE FROM $prefix$_");
 | 
			
		||||
        import_print "Importing $prefix$table ... (starting at line ".($.+2)." of $$opt{source})\n";
 | 
			
		||||
        my $imported = 0;
 | 
			
		||||
        TABLE: while (<IMPORT_FH>) {
 | 
			
		||||
            chomp;
 | 
			
		||||
            my $header = $_;
 | 
			
		||||
            my $delimiter = substr($header,0,1);
 | 
			
		||||
            substr($header,0,1) = '';
 | 
			
		||||
            my @cols = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $header, -1;
 | 
			
		||||
 | 
			
		||||
            if ($table =~ /Category$/) {
 | 
			
		||||
                push @cols, 'tmp_col';
 | 
			
		||||
            }
 | 
			
		||||
# If this is an ODBC db, we need to turn identity insert on.
 | 
			
		||||
            my $insert = "INSERT INTO $prefix$table (" . join(",", @cols) . ") VALUES (" . join(",",("?") x @cols) . ")";
 | 
			
		||||
            if ($odbc) {
 | 
			
		||||
                if ($DB->table($table)->ai) {
 | 
			
		||||
                    $insert = "SET IDENTITY_INSERT $prefix$table ON; $insert";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            my $sth = $e_dbh->prepare($insert) or critical "Unable to prepare query `$insert': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
            import_print "\tStarting import to table $prefix$table ...\n";
 | 
			
		||||
            while (<IMPORT_FH>) {
 | 
			
		||||
                last TABLE if substr($_,0,2) eq '\\\\';
 | 
			
		||||
                chomp;
 | 
			
		||||
                if ($table =~ /Category$/) {
 | 
			
		||||
                    print $_ . "\n";
 | 
			
		||||
                    my @data = map BK_unescape($_,$delimiter), split /\Q$delimiter/, $_, -1;
 | 
			
		||||
                    $sth->execute(@data) or warning "\tUnable to import `$_' (line $. of $$opt{source}): ".$sth->errstr;
 | 
			
		||||
                    import_print "\t$imported imported ...\n" unless ++$imported % 500;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "\t$imported records imported to $prefix$table.\n",
 | 
			
		||||
              "All records have been imported to $prefix$table.\n\n";
 | 
			
		||||
    }
 | 
			
		||||
    import_print "All tables contained in $$opt{source} have been imported.\n\nNOTE: You must run Repair Tables and Rebuild Search after performing an import!\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Takes two parameters: The field to escape, and the delimiter. It will return
 | 
			
		||||
# the field unescaped.
 | 
			
		||||
sub BK_unescape ($$) {
 | 
			
		||||
    my $field = shift;
 | 
			
		||||
    my $delimiter = shift;
 | 
			
		||||
    $delimiter = "" unless defined $delimiter;
 | 
			
		||||
    critical "Bad delimiter `$delimiter'" unless length $delimiter == 1 and $delimiter ne '\\';
 | 
			
		||||
    critical "An escaped field cannot be undefined. You have data errors!" unless defined $field;
 | 
			
		||||
    return undef if $field eq 'NULL';
 | 
			
		||||
    my $escape_chr = '\\';
 | 
			
		||||
    $field =~ s/\Q$escape_chr\E([0-9A-Fa-f]{2})/chr hex $1/ge;
 | 
			
		||||
    $field;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
2;
 | 
			
		||||
@@ -0,0 +1,581 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#	Website  : http://gossamer-threads.com/
 | 
			
		||||
#	Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#	Revision : $Id: CGI.pm,v 1.17 2005/04/05 08:44:30 brewt 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::Import::Interface::CGI;
 | 
			
		||||
# ==================================================================
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use Links qw/$IN $CFG/;
 | 
			
		||||
 | 
			
		||||
sub new {
 | 
			
		||||
    my $this = shift;
 | 
			
		||||
    my $class = ref($this) || $this;
 | 
			
		||||
    my $self = {};
 | 
			
		||||
    bless $self, $class;
 | 
			
		||||
    return $self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub isin {
 | 
			
		||||
    my $val = shift;
 | 
			
		||||
    for (@_) {
 | 
			
		||||
        return 1 if $val eq $_;
 | 
			
		||||
    }
 | 
			
		||||
    return undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub html_escape {
 | 
			
		||||
    shift if ref $_[0];
 | 
			
		||||
    my $to_escape = shift;
 | 
			
		||||
    $to_escape = "" unless defined $to_escape;
 | 
			
		||||
    $to_escape =~ s/&/&/g;
 | 
			
		||||
    $to_escape =~ s/ / /g;
 | 
			
		||||
    $to_escape =~ s/</</g;
 | 
			
		||||
    $to_escape =~ s/>/>/g;
 | 
			
		||||
    $to_escape =~ s/"/"/g;
 | 
			
		||||
    $to_escape;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub make_opts {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    return if ref $self->{cgi} eq 'HASH';
 | 
			
		||||
    $self->{cgi} = { };
 | 
			
		||||
    $self->{cgi}{help} = 1, return if $IN->param("help");
 | 
			
		||||
    return unless $IN->param("Interface_CGI");
 | 
			
		||||
 | 
			
		||||
    $self->{cgi}{transfer} = isin($IN->param("transfer"),qw/L1S2 L2S2 S1S2 BKS2 S2BK/)
 | 
			
		||||
                               ? $IN->param("transfer")
 | 
			
		||||
                               : "";
 | 
			
		||||
 | 
			
		||||
    for ($IN->param) { $self->{cgi}{$_} = $IN->param($_); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_options {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    $self->make_opts;
 | 
			
		||||
    return wantarray ? (help => 1) : { help => 1 } if $self->{cgi}{'help'};
 | 
			
		||||
    $self->start_page(),exit unless $IN->param("Interface_CGI");
 | 
			
		||||
    if ($self->{cgi}{'errors_to_browser'}) {
 | 
			
		||||
        if ($self->{cgi}{error_file}) {
 | 
			
		||||
            my $fh = \do { local *FH; *FH };
 | 
			
		||||
            unless (open $fh, "> $self->{cgi}{error_file}") {
 | 
			
		||||
                _print_headers();
 | 
			
		||||
                print "<pre>Unable to open error file @{[html_pre_format(qq($self->{cgi}{error_file}: $!))]}</pre>";
 | 
			
		||||
                exit;
 | 
			
		||||
            }
 | 
			
		||||
            $self->{cgi}{error_file} = sub {
 | 
			
		||||
                for (@_) {
 | 
			
		||||
                    print html_pre_format("Import error: $_\n");
 | 
			
		||||
                    print $fh "Import error: $_\n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $self->{cgi}{error_file} = sub {
 | 
			
		||||
                for (@_) {
 | 
			
		||||
                    print html_pre_format("Import error: $_\n");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        $self->{cgi}{error_file} = 'STDOUT';
 | 
			
		||||
    }
 | 
			
		||||
    return wantarray ? %{$self->{cgi}} : $self->{cgi};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub usage ($$$) {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    push @{$self->{usage_list}}, shift if @_;
 | 
			
		||||
# Don't care about the third argument; it is exclusively for Interface::Text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub has_usage {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    return ref $self->{usage_list} ? scalar @{$self->{usage_list}} : undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub show_usage {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    $self->start_page(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub pre_import {
 | 
			
		||||
    require Links;
 | 
			
		||||
    _print_headers();
 | 
			
		||||
    print "<html>\n<head>\n<title>Import Results</title>\n</head>\n<body bgcolor=#FFFFFF>\n";
 | 
			
		||||
    print Links::header("Import/Export", "Please be patient, this can take a while...");
 | 
			
		||||
    print "<blockquote><pre>";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub finished {
 | 
			
		||||
    print "</pre></blockquote>\n<b><font face='Tahoma,Arial,Helvetica' size=2>Data has been successfully import/exported!</font></b>\n</body>\n</html>";
 | 
			
		||||
    exit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes one optional argument which, if true, will make it print usage messages
 | 
			
		||||
sub start_page {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    $self->make_opts unless ref $self->{cgi} eq 'HASH';
 | 
			
		||||
    _print_headers();
 | 
			
		||||
    $self->_start_page_top;
 | 
			
		||||
    if (shift and ref $self->{usage_list} and @{$self->{usage_list}}) {
 | 
			
		||||
        print "\n\n<ul>\n";
 | 
			
		||||
        for (@{$self->{usage_list}}) {
 | 
			
		||||
            print "  <li><font color=red><b>$_ </b></font></li>\n";
 | 
			
		||||
        }
 | 
			
		||||
        print "</ul>\n\n";
 | 
			
		||||
    }
 | 
			
		||||
    $self->_start_page_bottom;
 | 
			
		||||
    exit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _start_page_top {
 | 
			
		||||
    print <<'HTML';
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<title>Gossamer Links Import</title>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body bgcolor="#FFFFFF">
 | 
			
		||||
<table border="1" cellpadding="0" cellspacing="0"><tr><td>
 | 
			
		||||
	<table bgColor="#ffffff" border="0" cellPadding="3" cellSpacing="3" width="500" valign="top">
 | 
			
		||||
	  <tr>
 | 
			
		||||
		<td align="left" bgColor="navy"><b><font color="#ffffff" size="2" face="Tahoma,Arial,Helvetica">Gossamer Links Import/Backup/Restore</font></b></td>
 | 
			
		||||
	  </tr>
 | 
			
		||||
	  <tr>
 | 
			
		||||
		<td>
 | 
			
		||||
		  <p align="center"><b><font color="#000000" size="2" face="Tahoma,Arial,Helvetica">Gossamer Links Import/Backup/Restore</font></b></p>
 | 
			
		||||
		  <p><font size="2" face="Tahoma,Arial,Helvetica">This tool will allow you to easily migrate from a previous
 | 
			
		||||
		  version of Links, or backup and restore your data. For more information on the specific options, please
 | 
			
		||||
		  consult the <b><a href="nph-import.cgi?help=1&Interface_CGI=1">Help</a></b></font></td>
 | 
			
		||||
	  </tr>
 | 
			
		||||
	</table>
 | 
			
		||||
	</td></tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
HTML
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _start_page_bottom {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    print qq[
 | 
			
		||||
  <form action="nph-import.cgi" method="POST">
 | 
			
		||||
  <input type=hidden name="Interface_CGI" value=1>
 | 
			
		||||
  <input type="hidden" name="destination" value="$CFG->{admin_root_path}/defs">
 | 
			
		||||
  <table border="1" cellspacing="0" cellpadding="0"><tr><td>
 | 
			
		||||
  <table border="0" cellspacing="0" cellpadding="3" width=500>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td colspan="2" bgcolor="#DDDDDD"><b><font face="Tahoma,Arial,Helvetica" size="2">Import Data from previous versions of Links</font></b></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          Import From:  
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left"><font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        <select size="1" name="transfer" style="font-family: Tahoma, Arial, Helvetica; font-size: 10pt; color: #000000">
 | 
			
		||||
          <option ];
 | 
			
		||||
    print "selected " if $self->{cgi}{transfer} and $self->{cgi}{transfer} eq "S1S2";
 | 
			
		||||
    print qq[value="S1S2">Links SQL 1.x</option>
 | 
			
		||||
          <option ];
 | 
			
		||||
    print "selected " if $self->{cgi}{transfer} and $self->{cgi}{transfer} eq "L1S2";
 | 
			
		||||
    print qq[value="L1S2">Links 1.x</option>
 | 
			
		||||
          <option ];
 | 
			
		||||
    print "selected " if $self->{cgi}{transfer} and $self->{cgi}{transfer} eq "L2S2";
 | 
			
		||||
    print qq[value="L2S2">Links 2.x</option>
 | 
			
		||||
        </select></font>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          Location of def files:
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <input type="text" name="source" size="40" ];
 | 
			
		||||
    print qq[value="].html_escape($self->{cgi}{source}).qq[" ] if $self->{cgi}{source} && ($self->{cgi}{transfer} =~ /^(?:L[12]|S1)S2$/);
 | 
			
		||||
    print qq[style="font-family: Tahoma, Arial, Helvetica; font-size: 10pt">
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          Error File (optional):
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <input type="text" name="error_file" size="40" ];
 | 
			
		||||
    print qq[value="].html_escape($self->{cgi}{error_file}).qq[" ] if $self->{cgi}{error_file} && ($self->{cgi}{transfer} =~ /^(?:L[12]|S1)S2$/);
 | 
			
		||||
    print qq[style="font-family: Tahoma, Arial, Helvetica; font-size: 10pt">
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </table>
 | 
			
		||||
  <table border="0" cellspacing="0" width="100%">
 | 
			
		||||
    <tr>
 | 
			
		||||
	  <td valign="top" align="left" colspan="6">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
		  <br><b>Options:</b>
 | 
			
		||||
		</font>
 | 
			
		||||
	   </td>
 | 
			
		||||
	</tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="show_mild_warnings" value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{show_mild_warnings};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Show Mild Warnings
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left" colspan=2>
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="critical_warnings" value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{critical_warnings};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Critical Warnings
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="data_integrity" value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{data_integrity};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Extra Data Integrity
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="clear_tables" value=1];
 | 
			
		||||
    print " checked" if not keys %{$self->{cgi}} or $self->{cgi}{clear_tables} and ($self->{cgi}{transfer} =~ /^(?:L[12]|S1)S2$/);
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Clear Tables
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left" colspan=2>
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="errors_to_browser" value=1];
 | 
			
		||||
    print " checked" if ($self->{cgi}{errors_to_browser} or not keys %{$self->{cgi}});
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Show Errors
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          <input type="checkbox" name="straight_import" value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{straight_import};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Straight Import
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign=top align=left colspan=2>
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size=2>
 | 
			
		||||
          <input type="checkbox" name="create_columns" value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{create_columns} or not keys %{$self->{cgi}};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Recreate Non-standard Columns
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign=top align=left colspan=2>
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size=2>
 | 
			
		||||
          <input type=checkbox name=create_missing_categories value=1];
 | 
			
		||||
    print " checked" if $self->{cgi}{create_missing_categories} or not keys %{$self->{cgi}};
 | 
			
		||||
    print qq[>
 | 
			
		||||
          Create Missing Categories
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td colspan="8"><br><center><input type="submit" value="Import Data"></center><br></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </table>
 | 
			
		||||
  </td></tr></table>
 | 
			
		||||
  </form>
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <form action="nph-import.cgi" method="POST">
 | 
			
		||||
  <input type=hidden name="Interface_CGI" value=1>
 | 
			
		||||
  <input type="hidden" name="source" value="$CFG->{admin_root_path}/defs">
 | 
			
		||||
  <input type="hidden" name="transfer" value="S2BK">
 | 
			
		||||
  <input type="hidden" name="delimiter" value="|">
 | 
			
		||||
  <table border="1" cellspacing="0" cellpadding="0"><tr><td>
 | 
			
		||||
  <table border="0" cellspacing="0" cellpadding="3" width=500>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td colspan="2" bgcolor="#DDDDDD"><b><font face="Tahoma,Arial,Helvetica" size="2">Create backup file of all Gossamer Links data</font></b></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          Location of Backup File:
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <input type="text" name="destination" size="40" ];
 | 
			
		||||
    print qq[value="].html_escape($self->{cgi}{destination}).qq[" ] if $self->{cgi}{destination} && ($self->{cgi}{transfer} eq 'S2BK');
 | 
			
		||||
    print qq[style="font-family: Tahoma, Arial, Helvetica; font-size: 10pt">
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td colspan="2"><br><center><input type="submit" value="Backup Data"></center><br></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </table>
 | 
			
		||||
  </td></tr></table>
 | 
			
		||||
  </form>
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <form action="nph-import.cgi" method="POST">
 | 
			
		||||
  <input type=hidden name="Interface_CGI" value=1>
 | 
			
		||||
  <input type="hidden" name="destination" value="$CFG->{admin_root_path}/defs">
 | 
			
		||||
  <input type="hidden" name="transfer" value="BKS2">
 | 
			
		||||
  <input type="hidden" name="delimiter" value="|">
 | 
			
		||||
  <input type="hidden" name="clear_tables" value="1">
 | 
			
		||||
  <table border="1" cellspacing="0" cellpadding="0"><tr><td>
 | 
			
		||||
  <table border="0" cellspacing="0" cellpadding="3" width=500>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td colspan="2" bgcolor="#DDDDDD"><b><font face="Tahoma,Arial,Helvetica" size="2">Restore Gossamer Links from backup file</font></b></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
          Location of Backup File:
 | 
			
		||||
        </font>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td valign="top" align="left">
 | 
			
		||||
        <input type="text" name="source" size="40" ];
 | 
			
		||||
    print qq[value="].html_escape($self->{cgi}{source}).qq[" ] if $self->{cgi}{source} && ($self->{cgi}{transfer} eq 'BKS2');
 | 
			
		||||
    print qq[style="font-family: Tahoma, Arial, Helvetica; font-size: 10pt">
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td colspan="2"><br><center><input type="submit" value="Restore Data"></center><br></td>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </table>
 | 
			
		||||
  </td></tr></table>
 | 
			
		||||
  </form>
 | 
			
		||||
  <br><br>
 | 
			
		||||
 | 
			
		||||
</form>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub show_help {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    _print_headers();
 | 
			
		||||
    print <<'HTML';
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<title>Gossamer Links Import Help</title>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body bgcolor="#FFFFFF">
 | 
			
		||||
<table border="1" cellpadding="0" cellspacing="0"><tr><td>
 | 
			
		||||
	<table bgColor="#ffffff" border="0" cellPadding="3" cellSpacing="3" width="500" valign="top">
 | 
			
		||||
	  <tr>
 | 
			
		||||
		<td align="left" bgColor="navy"><b><font color="#ffffff" size="2" face="Tahoma,Arial,Helvetica">Links
 | 
			
		||||
		  SQL Import Help</font></b></td>
 | 
			
		||||
	  </tr>
 | 
			
		||||
	  <tr>
 | 
			
		||||
		<td>
 | 
			
		||||
		  <p align="center"><b><font color="#000000" size="2" face="Tahoma,Arial,Helvetica">Links SQL Import Help</font></b></p>
 | 
			
		||||
		  <p><font size="2" face="Tahoma,Arial,Helvetica">Below is a list of all the options available to you when importing
 | 
			
		||||
		  data into Gossamer Links.</font></td>
 | 
			
		||||
	  </tr>
 | 
			
		||||
	</table>
 | 
			
		||||
	</td></tr>
 | 
			
		||||
</table>
 | 
			
		||||
<br><br>
 | 
			
		||||
<table cellpadding="3" cellspacing="0" border="1" width="500">
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        <b><u>Column</u></b>
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="center">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        <b><u>Description</u></b>
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Error File:
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        If present, all errors will be written to the filename provided. The
 | 
			
		||||
        errors will be appended to the end, with a header including the date
 | 
			
		||||
        written before any errors.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Show Mild Warnings
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        If this option is selected, 'mild' warnings (indicating minor errors
 | 
			
		||||
        such as setting the username associated with a link to 'admin' because
 | 
			
		||||
        of insufficient information to create a user) will be displayed in the
 | 
			
		||||
        error file. If unchecked, such errors are never displayed.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Critical Warnings
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        If this option is enabled, all warnings (such as not being able to
 | 
			
		||||
        import a Category or Link for whatever reason) will be promoted to
 | 
			
		||||
        critical errors, stopping the import. This field has NO effect on mild
 | 
			
		||||
        warnings - this is, mild warnings will NOT cause the script to abort.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Clear Tables
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        With this option enabled, all tables will be cleared before importing.
 | 
			
		||||
        This has no effect when exporting to a delimited text file.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Straight Import
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        With this option enabled, Link IDs will not be changed for the new
 | 
			
		||||
        database. That is, a Link with ID 12 in the old database will still be
 | 
			
		||||
        12 in the new Gossamer Links database. This option is not recommended unless
 | 
			
		||||
        you are linking directly to a link using its ID and must preserve the
 | 
			
		||||
        existing link numbering. This option <b>requires</b> that the <i>Clear
 | 
			
		||||
        Tables</i> option be enabled.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Show Warnings
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        With this option enabled, all warnings will be displayed to the
 | 
			
		||||
        browser (as well as the log if a log is specified). This option is
 | 
			
		||||
        automatically enabled if no log file is specified.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Recreate Non-standard Columns
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        If this option is enabled, when the import finds extra (custom) columns
 | 
			
		||||
        in the source database that do not have an equivelant extra column in
 | 
			
		||||
        the destination table, they will be created in the destination table so
 | 
			
		||||
        that all data will be imported.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Create Missing Categories
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        This option, if enabled, causes the import to create any categories
 | 
			
		||||
        that are "missing". A category can be missing when a category such as
 | 
			
		||||
        "A/B/C" exists, but the category "A/B" does not. This option will make
 | 
			
		||||
        the import create the "A/B" category, as well as the "A" category (if
 | 
			
		||||
        necessary (i.e. it doesn't exist)).<br>
 | 
			
		||||
        A category is also considered "missing" if a link refers to a category
 | 
			
		||||
        that does not exist (Links 1.x and 2.x only).
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td valign="top" align="left" width="25%">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        Extra Data Integrity
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td valign="top" align="left">
 | 
			
		||||
      <font face="Tahoma,Arial,Helvetica" size="2">
 | 
			
		||||
        This option makes the import check each time a category is imported to
 | 
			
		||||
        ensure that no duplicate categories will be created by the import. If a
 | 
			
		||||
        duplicate is identified, the duplicated category will only be inserted
 | 
			
		||||
        once. Note that this option will most likely make the script take
 | 
			
		||||
        several times longer to import data, and should only be used if you
 | 
			
		||||
        suspect that there may be duplicate categories.
 | 
			
		||||
      </font>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</table>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
HTML
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub html_pre_format {
 | 
			
		||||
    local $_ = shift;
 | 
			
		||||
    s/&/&/g;
 | 
			
		||||
    s/</</g;
 | 
			
		||||
    s/>/>/g;
 | 
			
		||||
    $_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
sub _print_headers {
 | 
			
		||||
# ------------------------------------------------------------------
 | 
			
		||||
# Prints the HTTP headers. Loads Links config file to see if we
 | 
			
		||||
# should use nph headers or not.
 | 
			
		||||
#
 | 
			
		||||
    print $IN->header ( -nph => $CFG->{nph_headers} );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"Do I *look* like a false value?"
 | 
			
		||||
@@ -0,0 +1,294 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Links SQL - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#	Website  : http://gossamer-threads.com/
 | 
			
		||||
#	Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#	Revision : $Id: Text.pm,v 1.14 2004/05/04 00:50:09 jagerman 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::Import::Interface::Text;
 | 
			
		||||
# ==================================================================
 | 
			
		||||
 | 
			
		||||
use vars qw/%IMPORT_OPT_MAP/;
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use Getopt::Long;
 | 
			
		||||
 | 
			
		||||
%IMPORT_OPT_MAP = (
 | 
			
		||||
    LINKSSQL1 => 'S1S2',
 | 
			
		||||
    LINKSQL1  => 'S1S2',
 | 
			
		||||
    LINKS1    => 'L1S2',
 | 
			
		||||
    LINKS2    => 'L2S2',
 | 
			
		||||
    S1        => 'S1S2',
 | 
			
		||||
    L2        => 'L2S2',
 | 
			
		||||
    L1        => 'L1S2',
 | 
			
		||||
    LINKS     => 'L2S2',
 | 
			
		||||
    RDF       => 'RDFS2',
 | 
			
		||||
    DMOZ      => 'RDFS2'
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
sub new {
 | 
			
		||||
    my $this = shift;
 | 
			
		||||
    my $class = ref($this) || $this;
 | 
			
		||||
    my $self = { };
 | 
			
		||||
    bless $self, $class;
 | 
			
		||||
    return $self;
 | 
			
		||||
    $self->_init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_options {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my %option = ();
 | 
			
		||||
    my ($backup,$restore,$import);
 | 
			
		||||
    GetOptions(
 | 
			
		||||
        "backup" => \$backup,
 | 
			
		||||
        "restore" => \$restore,
 | 
			
		||||
        "import=s" => \$import,
 | 
			
		||||
        "source=s" => \$option{source},
 | 
			
		||||
        "destination=s" => \$option{destination},
 | 
			
		||||
        "help" => \$option{help},
 | 
			
		||||
        "error-file=s" => \$option{error_file},
 | 
			
		||||
        "critical-warnings" => \$option{critical_warnings},
 | 
			
		||||
        "mild-warnings" => \$option{show_mild_warnings},
 | 
			
		||||
        "data-integrity" => \$option{data_integrity},
 | 
			
		||||
        "create-columns" => \$option{create_columns},
 | 
			
		||||
        "create-missing-categories" => \$option{create_missing_categories},
 | 
			
		||||
        "clear-tables" => \$option{clear_tables},
 | 
			
		||||
        "straight-import" => \$option{straight_import},
 | 
			
		||||
        "rdf-category=s" => \$option{rdf_category},
 | 
			
		||||
        "rdf-destination=s" => \$option{rdf_destination},
 | 
			
		||||
        "rdf-add-date=s" => \$option{rdf_add_date},
 | 
			
		||||
        "with-gzip=s" => \$option{with_gzip},
 | 
			
		||||
        "rdf-update" => \$option{rdf_update},
 | 
			
		||||
        "rdf-user=s" => \$option{rdf_user},
 | 
			
		||||
        "xml-parser!" => \$option{xml_parser}
 | 
			
		||||
    );
 | 
			
		||||
    $option{transfer} = $IMPORT_OPT_MAP{uc $import} || "";
 | 
			
		||||
    unless ($option{from} or $option{to} or $option{source} or $option{destination}) {
 | 
			
		||||
        return wantarray ? () : {};
 | 
			
		||||
    }
 | 
			
		||||
    if (($backup and $restore) or ($backup and $option{transfer}) or ($restore and $option{transfer})) {
 | 
			
		||||
        delete $option{transfer}; # Two options provided!
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($backup) {
 | 
			
		||||
        $option{transfer} = "S2BK";
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($restore) {
 | 
			
		||||
        $option{transfer} = "BKS2";
 | 
			
		||||
    }
 | 
			
		||||
    return wantarray ? %option : \%option;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub start_page {
 | 
			
		||||
    show_help(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub show_help {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    print <<HELP;
 | 
			
		||||
 | 
			
		||||
Links SQL 2 Importer/Exporter
 | 
			
		||||
 | 
			
		||||
Usage:
 | 
			
		||||
 | 
			
		||||
perl $0 {--backup|--restore|--import type} --source=<source>
 | 
			
		||||
        --destination=<destination> [any others of the following options]
 | 
			
		||||
 | 
			
		||||
Options are (options may be simplified to uniqueness):
 | 
			
		||||
 | 
			
		||||
(One of the following three is required)
 | 
			
		||||
    --import Links1|Links2|LinksSQL1|RDF
 | 
			
		||||
        Will do an import from the chosen source.
 | 
			
		||||
 | 
			
		||||
    --backup
 | 
			
		||||
        This option will perform a Links SQL 2 backup.
 | 
			
		||||
 | 
			
		||||
    --restore
 | 
			
		||||
        This option will return from a Links SQL 2 backup file created
 | 
			
		||||
        with --backup.
 | 
			
		||||
 | 
			
		||||
    --source=<input_source> (required)
 | 
			
		||||
        Sets according to the following:
 | 
			
		||||
        --import Links1|Links2
 | 
			
		||||
            the path of the def and db files
 | 
			
		||||
        --import LinksSQL1
 | 
			
		||||
            the path of the def files
 | 
			
		||||
        --import RDF
 | 
			
		||||
            the path and filename of the RDF file to import from.
 | 
			
		||||
            Note that if the file ends in .gz, the import will attempt to run
 | 
			
		||||
            it through gzip decompression trying several standard locations for
 | 
			
		||||
            gzip. You may specify a location for gzip using the --with-gzip
 | 
			
		||||
            option.
 | 
			
		||||
        --restore
 | 
			
		||||
            the path and filename of the backup file created with --backup
 | 
			
		||||
        --backup
 | 
			
		||||
            the path of the Links SQL 2 def files
 | 
			
		||||
 | 
			
		||||
    --destination=<output_dest> (required)
 | 
			
		||||
        Sets according to the following:
 | 
			
		||||
        --import Links1|Links2|LinksSQL1|RDF
 | 
			
		||||
        --restore
 | 
			
		||||
            the path of the Links SQL 2 def files
 | 
			
		||||
        --backup
 | 
			
		||||
            the path and filename of a file to use for the Links SQL 2 backup.
 | 
			
		||||
 | 
			
		||||
    --error-file="./error/errors.txt" (not required)
 | 
			
		||||
        Sets a file to which all import errors will be written. If you set it
 | 
			
		||||
        to STDOUT, or if it is not set, it will write all errors to standard
 | 
			
		||||
        output (STDOUT) prepended with "IMPORT ERROR: ".
 | 
			
		||||
    
 | 
			
		||||
    --critical-warnings
 | 
			
		||||
        Makes import warnings become fatal errors. Note that relatively minor
 | 
			
		||||
        warnings such as not having enough information to create a new user for
 | 
			
		||||
        a link (therefore setting the link to be owned by admin) are not
 | 
			
		||||
        promoted to fatal errors.
 | 
			
		||||
 | 
			
		||||
    --mild-warnings
 | 
			
		||||
        Displays mild import warnings. Mild warnings are those that affect a
 | 
			
		||||
        relatively minor portion of the script. Note that mild warnings will
 | 
			
		||||
        NOT cause the script to abort, even if the --critical-warnings option
 | 
			
		||||
        has been enabled.
 | 
			
		||||
    
 | 
			
		||||
    --data-integrity
 | 
			
		||||
        Makes the import check every category before inserting it to insure
 | 
			
		||||
        that there are no duplicates. Note that this option will make the
 | 
			
		||||
        import take much longer to complete as each and every category will
 | 
			
		||||
        have to be checked to see if it exists. This option is only recommended
 | 
			
		||||
        if you suspect that your data might contain duplicate categories. It
 | 
			
		||||
        only works when importing data to a Links SQL 2 database from Links
 | 
			
		||||
        1.x, Links 2.x, or Links SQL 1.x (NOT when backing up, restoring, or
 | 
			
		||||
        importing from an RDF).
 | 
			
		||||
 | 
			
		||||
    --create-columns
 | 
			
		||||
        Makes the import attempt to create any columns which are in the source
 | 
			
		||||
        tables, but NOT in the destination tables. That is, custom tables will
 | 
			
		||||
        be imported into the new Links database. Without this option, existing
 | 
			
		||||
        tables that do not exist in the destination format will cause a
 | 
			
		||||
        warning. If this feature is enabled, a mild warning will occur whenever
 | 
			
		||||
        a table does not exist and is being created.
 | 
			
		||||
 | 
			
		||||
    --clear-tables
 | 
			
		||||
        (This option is required to use --restore, but optional for --backup
 | 
			
		||||
         and all imports)
 | 
			
		||||
        Makes the current Links SQL tables be cleared (except for the admin
 | 
			
		||||
        user in the Users table) before doing the import. Only takes effect
 | 
			
		||||
        when importing to Links SQL 2. This option allows you to use the
 | 
			
		||||
        --straight-import option below.
 | 
			
		||||
 | 
			
		||||
    --straight-import
 | 
			
		||||
        (This option can only be used with --clear-tables).
 | 
			
		||||
        Makes the import not recalculate Category/Link ID numbers. That is, a
 | 
			
		||||
        link with ID number 12 in the source will be inserted into the Links
 | 
			
		||||
        SQL 2 database with an ID number of 12. Note that this can leave a
 | 
			
		||||
        fairly large gap in the Links ID fields depending on the usage of the
 | 
			
		||||
        source import. This option does nothing with --backup and --restore
 | 
			
		||||
 | 
			
		||||
    --create-missing-categories
 | 
			
		||||
        Used with an import. Categories are "missing" when they are required
 | 
			
		||||
        for the database to be complete but do not exist. For example, if 
 | 
			
		||||
        category A/B/C existed in the database but A and A/B did not, then both
 | 
			
		||||
        A and A/B would be considered "missing" and would be automatically
 | 
			
		||||
        created if this option is enabled. For Links 1.x and 2.x imports, this
 | 
			
		||||
        will also make the import attempt to create categories that are
 | 
			
		||||
        required for links. For example, if a link exists and thinks it is in
 | 
			
		||||
        category A/B/C but A/B does no exist, A/B and A/B/C will be created to
 | 
			
		||||
        allow the link to be imported.
 | 
			
		||||
 | 
			
		||||
    --rdf-category="Top/Category/Name"
 | 
			
		||||
        (This option can only be and must be used with `--import RDF')
 | 
			
		||||
        Specifies the RDF category to import such as "Top/Business".
 | 
			
		||||
 | 
			
		||||
    --rdf-destination="Links SQL2/Category/Name"
 | 
			
		||||
        (This option can only be used with `--import RDF')
 | 
			
		||||
        Specifies a Links SQL 2 category to import the data to. For example,
 | 
			
		||||
        "My Business Links" would import the RDF category specified with
 | 
			
		||||
        --rdf-category into the "My Business Links" category. If this is not
 | 
			
		||||
        specified (or specified as "/" or "") the import will be done into the
 | 
			
		||||
        Links SQL category root.
 | 
			
		||||
 | 
			
		||||
    --with-gzip="/path/to/gzip"
 | 
			
		||||
        (This option can only be used with `--import RDF')
 | 
			
		||||
        Specifies the location of gzip. This option is only needed if the RDF
 | 
			
		||||
        file has been compressed with gzip (the file will end with ".gz") and
 | 
			
		||||
        the import is unable to locate gzip on its own.
 | 
			
		||||
 | 
			
		||||
    --rdf-update
 | 
			
		||||
        (This option can only be used with `--import RDF')
 | 
			
		||||
        Specifies that the import should check to see that categories and links
 | 
			
		||||
        do not already exist. For an initial RDF import, this option is not
 | 
			
		||||
        needed, however to update a previous RDF import you MUST use this
 | 
			
		||||
        option; failing to do so would result in duplicate categories and links
 | 
			
		||||
        appearing. It is not recommended that you use this option when
 | 
			
		||||
        performing an initial import from an RDF as it will increase the import
 | 
			
		||||
        time considerably.
 | 
			
		||||
 | 
			
		||||
    --rdf-user="Username"
 | 
			
		||||
        (This option can only be used with `--import RDF')
 | 
			
		||||
        Specifies a user who all new links should belong to. The user MUST
 | 
			
		||||
        already exist in the Links SQL Users table. If not specified, all links
 | 
			
		||||
        will have `admin' as the LinkOwner. Note that if the --clear-tables
 | 
			
		||||
        option is specified, this user will also be preserved when all tables
 | 
			
		||||
        are wiped.
 | 
			
		||||
 | 
			
		||||
    --rdf-add-date="2001-01-05"
 | 
			
		||||
        (This option can only be used with `--import RDF' and is required)
 | 
			
		||||
        This sets the date that new link links should have their `Add_Date' and
 | 
			
		||||
        `Mod_Date' fields set to. This should be in the format `YYYY-MM-DD'.
 | 
			
		||||
        NOTE: You should NOT set this to a very recent date as all links would
 | 
			
		||||
        then show up as "New" links.
 | 
			
		||||
 | 
			
		||||
    --help
 | 
			
		||||
        Displays this screen
 | 
			
		||||
 | 
			
		||||
HELP
 | 
			
		||||
 | 
			
		||||
# Understood, but often fails as RDF files are commonly malformed:
 | 
			
		||||
#
 | 
			
		||||
#    --xml-parser
 | 
			
		||||
#        (This option can only be used with `--import RDF')
 | 
			
		||||
#        Attempts to use the new XML::Parser-based code for importing the RDF
 | 
			
		||||
#        file.  Although much faster, it requires that the XML::Parser module be
 | 
			
		||||
#        installed, and should be considered an experimental feature.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub pre_import () { }
 | 
			
		||||
 | 
			
		||||
sub usage ($$;$) {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    $self->{usage_list} = [ ] unless exists $self->{usage_list};
 | 
			
		||||
    my $message = "";
 | 
			
		||||
    if (@_) {
 | 
			
		||||
        $message = shift() . ".";
 | 
			
		||||
        $message .= " See " . shift() . " and --help" if @_;
 | 
			
		||||
    }
 | 
			
		||||
    push @{$self->{usage_list}}, $message if $message;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub has_usage {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    return ref($self->{usage_list}) ? scalar @{$self->{usage_list}} : undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub show_usage {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    for (@{$self->{usage_list}}) { print <<USAGE }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Incorrect usage.
 | 
			
		||||
 | 
			
		||||
$_
 | 
			
		||||
 | 
			
		||||
USAGE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub finished () {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    print "\n\nImport completed successfully\n";
 | 
			
		||||
    exit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"Apparently, I'm true";
 | 
			
		||||
							
								
								
									
										689
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/L1S2.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										689
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/L1S2.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,689 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#	Website  : http://gossamer-threads.com/
 | 
			
		||||
#	Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#	Revision : $Id: L1S2.pm,v 1.25 2005/04/16 02:11:50 brewt 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::Import::L1S2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my ($have_email_db,$have_validate_db);
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $e_prefix = $DB->prefix;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    local (*LINKS,*CATS,*EMAIL,$@,$!,*VALIDATE);
 | 
			
		||||
 | 
			
		||||
# Check to see if this should be a Links SQL 1.x import instead of Links 1.x.
 | 
			
		||||
    my $error_msg = "";
 | 
			
		||||
    -e "$$opt{source}/links.cfg" or $error_msg .= "$$opt{source}/links.cfg does not exist.";
 | 
			
		||||
    -e "$$opt{source}/Links.def" and $error_msg .= " $$opt{source}/Links.def DOES exist. Perhaps you meant to import Links SQL 1.x instead of Links 1.x?";
 | 
			
		||||
    critical $error_msg if $error_msg;
 | 
			
		||||
 | 
			
		||||
    my $did = do {
 | 
			
		||||
        package Links1::Def::Links; # Avoid namespace pollution
 | 
			
		||||
        do "$$opt{source}/links.cfg";
 | 
			
		||||
    };
 | 
			
		||||
    !$did and $! and critical "Cannot open $$opt{source}/links.cfg (This error may result from links.def): $!".($@ ? ", ".substr($@,0,length($@)-1) : "");
 | 
			
		||||
    !$did and $@ and critical "Cannot parse $$opt{source}/links.cfg (This error may result from links.def): $@";
 | 
			
		||||
    $Links1::Def::Links::db_file_name or critical "links.cfg did not load correctly. Import aborted.";
 | 
			
		||||
 | 
			
		||||
    $did = do {
 | 
			
		||||
        package Links1::Def::Category;
 | 
			
		||||
        local $ENV{PATH_INFO} = "/category";
 | 
			
		||||
        do "$$opt{source}/links.cfg";
 | 
			
		||||
    };
 | 
			
		||||
    !$did and $! and critical "Cannot open $$opt{source}/links.cfg (This error may result from category.def): $!".($@ ? ", ".substr($@,0,length($@)-1) : "");
 | 
			
		||||
    !$did and $@ and critical "Cannot parse $$opt{source}/links.cfg (This error may result from category.def): $@";
 | 
			
		||||
    $Links1::Def::Category::db_file_name or critical "links.cfg did not load correctly. Import aborted.";
 | 
			
		||||
 | 
			
		||||
    open CATS, "<$Links1::Def::Category::db_file_name" or critical "Unable to open $Links1::Def::Links::db_file_name: $!";
 | 
			
		||||
    open LINKS, "<$Links1::Def::Links::db_file_name" or critical "Unable to open $Links1::Def::Links::db_file_name: $!";
 | 
			
		||||
    if (open VALIDATE, "<$Links1::Def::Links::db_valid_name") {
 | 
			
		||||
        $have_validate_db = 1;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        warning "Could not open $Links1::Def::Links::db_valid_name: $!. Non-validated links will not be imported.";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %e_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name FatherID Full_Name Description Meta_Description Meta_Keywords Header Footer Category_Template Number_of_Links Has_New_Links Has_Changed_Links Newest_Link Timestmp Payment_Mode/},
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL LinkOwner Add_Date Mod_Date Description Contact_Name Contact_Email Hits isNew isChanged isPopular isValidated Rating Votes Status Date_Checked Timestmp ExpiryDate ExpiryCounted ExpiryNotify/},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %e_non_standard_cols;
 | 
			
		||||
    for my $table (keys %e_standard_cols) {
 | 
			
		||||
        my %cols = $DB->table($table)->cols;
 | 
			
		||||
        for (grep !$e_standard_cols{$table}{$_}, keys %cols) {
 | 
			
		||||
            $e_non_standard_cols{$table}{$_} = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %i_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name Description Related Header Footer/,'Meta Description','Meta Keywords' },
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL Date Category Description Hits isNew isPopular/,'Contact Name','Contact Email'}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %i_non_standard_cols;
 | 
			
		||||
    $i_non_standard_cols{Links} = { map { !$i_standard_cols{Links}{$_} ? ($_ => 1) : () } @Links1::Def::Links::db_cols };
 | 
			
		||||
    $i_non_standard_cols{Category} = { map { !$i_standard_cols{Category}{$_} ? ($_ => 1) : () } @Links1::Def::Category::db_cols };
 | 
			
		||||
 | 
			
		||||
    my $Links_counter;
 | 
			
		||||
    my $Category_counter;
 | 
			
		||||
    if (($DB->table('Links')->{connect}->{driver} || "") eq "ODBC") {
 | 
			
		||||
        $e_dbh->do("SET IDENTITY_INSERT Links ON");
 | 
			
		||||
        $e_dbh->do("SET IDENTITY_INSERT Category ON");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($$opt{clear_tables}) {
 | 
			
		||||
    # Delete everything from all tables, EXCEPT for the `admin' user from the Users table
 | 
			
		||||
        $e_dbh->do("DELETE FROM ${e_prefix}Users WHERE Username <> 'admin'") or critical "Unable to delete all existing users: ".$e_dbh->errstr;
 | 
			
		||||
        for (qw/Links Category CatLinks CatRelations Category_Score_List
 | 
			
		||||
            Category_Word_List ClickTrack Editors EmailMailings EmailTemplates
 | 
			
		||||
            Links_Score_List Links_Word_List MailingIndex MailingList
 | 
			
		||||
            MailingListIndex Sessions Verify/) {
 | 
			
		||||
            $e_dbh->do("DELETE FROM $e_prefix$_");
 | 
			
		||||
        }
 | 
			
		||||
        unless ($$opt{straight_import}) {
 | 
			
		||||
            $Links_counter = $Category_counter = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        my $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Links") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$sth->errstr;
 | 
			
		||||
        $Links_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
 | 
			
		||||
        $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$sth->errstr;
 | 
			
		||||
        $Category_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Categories
 | 
			
		||||
    my %cat_map; # $cat_map{name} = new_id
 | 
			
		||||
    my @num_of_links; # $num_of_links[category_id] = (the number of links in that category)
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        my @cat_get_cols = ('ID','Name','Related',       'Description','Meta Description','Meta Keywords','Header','Footer');
 | 
			
		||||
        my $cat_ins_cols = "(ID, Name, FatherID, Full_Name, Description, Meta_Description, Meta_Keywords, Header, Footer";
 | 
			
		||||
        my $cat_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        # Build up extra fields that exist in both old and new Category tables
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Category"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Category}{$_}) {
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                push @cat_get_cols, $_;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Category.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Category"}{$_}, keys %{$i_non_standard_cols{Category}}) {
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                if (/\W/) {
 | 
			
		||||
                    critical "Custom import column `Category.$_' cannot be imported because is is not a valid column name. You will need to rename the column name in the def file and in any relevant templates to a new name consisting only of letters, numbers, and the _ character.";
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                mild_warning("Custom import column `Category.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Category");
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => 'TEXT',
 | 
			
		||||
                        size                  => $Links1::Def::Category::db_max_field_length,
 | 
			
		||||
                        ($Links1::Def::Category::db_not_null{$_}    ? (not_null => 1)                                       : ()),
 | 
			
		||||
                        ($Links1::Def::Category::db_defaults{$_}    ? (default  => $Links1::Def::Category::db_defaults{$_}) : ()),
 | 
			
		||||
                        ($Links1::Def::Category::db_valid_types{$_} ? (regex => $Links1::Def::Category::db_valid_types{$_}) : ()),
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                push @cat_get_cols, $_;
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Category"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Category.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $cat_ins_cols .= ")";
 | 
			
		||||
        $cat_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
        my $add_cat_relation = $e_dbh->prepare("INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
        my $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_ins_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_ins_simple_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
        my $get_id_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        my @cat_relations;
 | 
			
		||||
 | 
			
		||||
        my $cat_imported = 0;
 | 
			
		||||
        import_print "\nImporting Categories ...\n";
 | 
			
		||||
        my @cat_data;
 | 
			
		||||
        while (my $row = get_rec(\*CATS,'Category',\@Links1::Def::Category::db_cols,"|",\@cat_get_cols)) {
 | 
			
		||||
            push @cat_data, $row if ref $row eq 'ARRAY';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @cat_data = sort { $a->[1] cmp $b->[1] } @cat_data;
 | 
			
		||||
 | 
			
		||||
        my @missing_cats;
 | 
			
		||||
        my %missing_cats;
 | 
			
		||||
        for my $row (@cat_data) {
 | 
			
		||||
            $row = [@$row];
 | 
			
		||||
            my $old_id = shift @$row;
 | 
			
		||||
            my $new_id = $$opt{straight_import} ? $old_id : ++$Category_counter;
 | 
			
		||||
            my ($name) = (my $full_name = shift @$row) =~ m[([^/]*)\Z];
 | 
			
		||||
            unless (defined $name and length $name) {
 | 
			
		||||
                $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                warning "Cannot insert Category $full_name because it is an invalid name";
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
            my ($father_full_name) = $full_name =~ m[\A(.*)/];
 | 
			
		||||
            my $father_id;
 | 
			
		||||
            if (not defined $father_full_name) {
 | 
			
		||||
                $father_id = 0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $get_id_sth->execute($father_full_name) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_id_sth->errstr;
 | 
			
		||||
                if (my $ar = $get_id_sth->fetchrow_arrayref()) {
 | 
			
		||||
                    $father_id = $ar->[0] || 0;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    if ($$opt{create_missing_categories}) {
 | 
			
		||||
                        unless ($missing_cats{$father_full_name}++) {
 | 
			
		||||
                            unshift @missing_cats, $father_full_name;
 | 
			
		||||
                            mild_warning "$father_full_name is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                            my $fn = $father_full_name;
 | 
			
		||||
                            while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                                $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                                if ($count_cats_sth->fetchrow_array or $missing_cats{$fn}++) { # It exists
 | 
			
		||||
                                    last;
 | 
			
		||||
                                }
 | 
			
		||||
                                else {
 | 
			
		||||
                                    unshift @missing_cats, $fn;
 | 
			
		||||
                                    mild_warning "$fn is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            mild_warning "$father_full_name is also needed for category $full_name and is already in the queue to be created.";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        warning "No father row found for $full_name! This may be a serious error as $full_name should probably have a father category";
 | 
			
		||||
                    }
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $cat_relations[$new_id] = shift @$row; # This has to be dealt with later.
 | 
			
		||||
 | 
			
		||||
            if ($$opt{data_integrity}) {
 | 
			
		||||
                $count_cats_sth->execute($full_name) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                unless ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                    unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                        $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                        warning "Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr;
 | 
			
		||||
                        next;
 | 
			
		||||
                    }
 | 
			
		||||
                    import_print "$cat_imported\n" unless ++$cat_imported % 500;
 | 
			
		||||
                    $cat_map{$full_name} = $new_id;
 | 
			
		||||
                    $num_of_links[$new_id] = 0;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    mild_warning("Duplicate category found ($full_name) and skipped");
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr);
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                import_print "$cat_imported\n" unless ++$cat_imported % 500;
 | 
			
		||||
                $cat_map{$full_name} = $new_id;
 | 
			
		||||
                $num_of_links[$new_id] = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        my $missing_cats;
 | 
			
		||||
        if ($$opt{create_missing_categories} and @missing_cats) {
 | 
			
		||||
            my $counter = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category");
 | 
			
		||||
            $counter->execute();
 | 
			
		||||
            my $ins_id = $counter->fetchrow_array();
 | 
			
		||||
            my $update_sub_cats = $e_dbh->prepare("UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?': ".$e_dbh->errstr;
 | 
			
		||||
            for (@missing_cats) {
 | 
			
		||||
                my ($name) = m[([^/]*)\Z];
 | 
			
		||||
                my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                my $father_id;
 | 
			
		||||
                if ($father_full) {
 | 
			
		||||
                    $get_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_id_sth->errstr;
 | 
			
		||||
                    $father_id = $get_id_sth->fetchrow_array;
 | 
			
		||||
                }
 | 
			
		||||
                else { # Must be a category of root
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
                $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                $cat_map{$_} = $ins_id;
 | 
			
		||||
                $update_sub_cats->execute($ins_id,"$_/%","$_/%/%") or critical "Unable to execute query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? and Full_Name NOT LIKE ?': ".$update_sub_cats->errstr;
 | 
			
		||||
                $missing_cats++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "$cat_imported Categories imported";
 | 
			
		||||
        import_print ", $missing_cats missing categories created" if $missing_cats;
 | 
			
		||||
        import_print ".\n";
 | 
			
		||||
 | 
			
		||||
# Category Relations
 | 
			
		||||
        import_print "\nImporting Category Relations ...\n";
 | 
			
		||||
        my $cat_rel_imported = 0;
 | 
			
		||||
        for my $cat_id (0..$#cat_relations) {
 | 
			
		||||
            next unless defined $cat_relations[$cat_id];
 | 
			
		||||
            my @cats = split /\|/, $cat_relations[$cat_id];
 | 
			
		||||
            for (@cats) {
 | 
			
		||||
                $get_id_sth->execute($_) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_id_sth->errstr;
 | 
			
		||||
                my $rel_id = $get_id_sth->fetchrow_array;
 | 
			
		||||
                if (defined $rel_id) {
 | 
			
		||||
                    unless ($add_cat_relation->execute($cat_id,$rel_id)) {
 | 
			
		||||
                        warning "Unable to execute query `INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)': ".$add_cat_relation->errstr;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        import_print "$cat_rel_imported\n" unless ++$cat_rel_imported % 500;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    warning "Unable to add category relation for category with ID $cat_id and `$_'. Reason: Category `$_' not found in database.";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$cat_rel_imported Category Relations imported.\n";
 | 
			
		||||
    }
 | 
			
		||||
# Links
 | 
			
		||||
    {
 | 
			
		||||
        my @links_get_cols = ('ID','Category','Date','Contact Name','Contact Email',                     qw/Title  URL  Description  Hits  isNew  isPopular/);
 | 
			
		||||
        my $links_ins_cols = "(ID, LinkOwner, isValidated, Add_Date, Mod_Date, Contact_Name, Contact_Email, Title, URL, Description, Hits, isNew, isPopular";
 | 
			
		||||
        my $links_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Links"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Links}{$_}) {
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                push @links_get_cols, $_;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Links.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep $e_standard_cols{Links}{$_}, keys %{$i_non_standard_cols{Links}}) {
 | 
			
		||||
            $links_ins_cols .= ", $_";
 | 
			
		||||
            $links_ins_vals .= ", ?";
 | 
			
		||||
            push @links_get_cols, $_;
 | 
			
		||||
        }
 | 
			
		||||
        for (grep +(!$e_standard_cols{Links} and !$e_non_standard_cols{"${e_prefix}Links"}{$_}), keys %{$i_non_standard_cols{Links}}) {
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Links.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Links");
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => 'TEXT',
 | 
			
		||||
                        size                  => $Links1::Def::Links::db_max_field_length,
 | 
			
		||||
                        ($Links1::Def::Links::db_not_null{$_}    ? (not_null => 1)                                    : ()),
 | 
			
		||||
                        ($Links1::Def::Links::db_defaults{$_}    ? (default  => $Links1::Def::Links::db_defaults{$_}) : ()),
 | 
			
		||||
                        ($Links1::Def::Links::db_valid_types{$_} ? (regex => $Links1::Def::Links::db_valid_types{$_}) : ()),
 | 
			
		||||
                    }
 | 
			
		||||
                ) or critical("Unable to add column $_: $GT::SQL::error");
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                push @links_get_cols, $_;
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Links"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Links.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $links_ins_cols .= ")";
 | 
			
		||||
        $links_ins_vals .= ")";
 | 
			
		||||
        my $user_ins_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Registered')") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Registered')': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_links_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$e_dbh->errstr);
 | 
			
		||||
        my $insert_link_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        my $user_count_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $username_sth = $e_dbh->prepare("SELECT Username FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT Username FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        # What other than the Name and ReceiveMail can be updated here?
 | 
			
		||||
        my $user_mod_sth = $e_dbh->prepare("UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $num_links_sth = $e_dbh->prepare("UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my ($count_cats_sth,$get_cat_id_sth,$cat_ins_simple_sth);
 | 
			
		||||
        my $ins_id;
 | 
			
		||||
        if ($$opt{create_missing_categories}) {
 | 
			
		||||
            $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
            $get_cat_id_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
            $cat_ins_simple_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
            my $counter = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category");
 | 
			
		||||
            $counter->execute();
 | 
			
		||||
            $ins_id = $counter->fetchrow_array();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "\nImporting Links ...\n";
 | 
			
		||||
        my $links_imported = 0;
 | 
			
		||||
        my $missing_cats = 0;
 | 
			
		||||
        my @more_needed; # This will hold any missing categories (such as A/B in A/B/C)
 | 
			
		||||
  LINK: while (my $row = get_rec(\*LINKS,'Links',\@Links1::Def::Links::db_cols,"|",\@links_get_cols)) {
 | 
			
		||||
            $row = [@$row]; # Remove aliasing
 | 
			
		||||
            my ($id, $cat_name, $date, $contact_name, $contact_email) = splice @$row,0,5;
 | 
			
		||||
            unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
            $date = convert_date($date) or warning("Invalid date `$date' for link with ID $id. Link skipped."),next;
 | 
			
		||||
            $id = ++$Links_counter unless $$opt{straight_import};
 | 
			
		||||
            my $cat_id = $cat_map{$cat_name};
 | 
			
		||||
            unless (defined $cat_id) {
 | 
			
		||||
                if ($$opt{create_missing_categories} and $cat_name) {
 | 
			
		||||
                    my @needed = my $fn = $cat_name;
 | 
			
		||||
                    while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                        $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                        if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                            last;
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            unshift @needed, $fn;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    for (@needed) {
 | 
			
		||||
                        my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                        unless ($name) {
 | 
			
		||||
                            warning "Unable to create category $_ because it is an invalid name. Link ID $id will be skipped as a result.";
 | 
			
		||||
                            last;
 | 
			
		||||
                        }
 | 
			
		||||
                        mild_warning("Creating category $_ as it is needed by link ID $id");
 | 
			
		||||
                        my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                        my $father_id;
 | 
			
		||||
                        if ($father_full) {
 | 
			
		||||
                            $get_cat_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_cat_id_sth->errstr;
 | 
			
		||||
                            $father_id = $get_cat_id_sth->fetchrow_array;
 | 
			
		||||
                        }
 | 
			
		||||
                        else { # Must be a root category
 | 
			
		||||
                            $father_id = 0;
 | 
			
		||||
                        }
 | 
			
		||||
                        $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                        $cat_map{$_} = $ins_id;
 | 
			
		||||
                        $cat_id = $ins_id;
 | 
			
		||||
                        $missing_cats++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    warning("Invalid category `$cat_name' for link $$row[0] (ID: $id, line $.). Link skipped"),next unless defined $cat_id;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            next LINK unless defined $cat_id;
 | 
			
		||||
            my $username;
 | 
			
		||||
            $user_count_sth->execute($contact_email) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
            if ($user_count_sth->fetchrow_arrayref()->[0]) { # This e-mail address already exists
 | 
			
		||||
                $user_mod_sth->execute($contact_name, $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
            }
 | 
			
		||||
            elsif ($contact_email) {
 | 
			
		||||
                $user_ins_sth->execute(($contact_email) x 2, (defined $contact_name ? $contact_name : ""), 'Yes') or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Registered')': ".$user_ins_sth->errstr);
 | 
			
		||||
                $username = $contact_email;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                $username = 'admin';
 | 
			
		||||
            }
 | 
			
		||||
            if ($insert_link_sth->execute($id,$username,'Yes',$date,$date,@$row)) {
 | 
			
		||||
                $cat_links_sth->execute($id,$cat_id) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                $num_of_links[$cat_id]++;
 | 
			
		||||
 | 
			
		||||
                import_print "$links_imported\n" unless ++$links_imported % 500;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $Links_counter-- unless $$opt{straight_import};
 | 
			
		||||
                warning("Unable to insert link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals'): ".$insert_link_sth->errstr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$links_imported records from 'Links' imported.\n";
 | 
			
		||||
 | 
			
		||||
        if ($have_validate_db) {
 | 
			
		||||
            $links_imported = 0;
 | 
			
		||||
            import_print "Importing records from 'Validate'.\n";
 | 
			
		||||
 | 
			
		||||
      LINK: while(my $row = get_rec(\*VALIDATE,'Links',\@Links1::Def::Links::db_cols,"|",\@links_get_cols)) {
 | 
			
		||||
                $row = [@$row]; # Remove aliasing
 | 
			
		||||
                my ($id, $cat_name, $date, $contact_name, $contact_email) = splice @$row,0,5;
 | 
			
		||||
                unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
                $date = convert_date($date) or warning("Invalid date `$date' for link with ID $id. Link skipped."),next;
 | 
			
		||||
                $id = ++$Links_counter unless $$opt{straight_import};
 | 
			
		||||
                my $cat_id = $cat_map{$cat_name};
 | 
			
		||||
                unless (defined $cat_id) {
 | 
			
		||||
                    if ($$opt{create_missing_categories} and $cat_name) {
 | 
			
		||||
                        my @needed = my $fn = $cat_name;
 | 
			
		||||
                        while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                            $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                            if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                                last;
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                unshift @needed, $fn;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        for (@needed) {
 | 
			
		||||
                            my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                            unless ($name) {
 | 
			
		||||
                                warning "Unable to create category $_ because it is an invalid name. Link ID $id will be skipped as a result.";
 | 
			
		||||
                                last;
 | 
			
		||||
                            }
 | 
			
		||||
                            mild_warning("Creating category $_ as it is needed by link ID $id");
 | 
			
		||||
                            my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                            my $father_id;
 | 
			
		||||
                            if ($father_full) {
 | 
			
		||||
                                $get_cat_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_cat_id_sth->errstr;
 | 
			
		||||
                                $father_id = $get_cat_id_sth->fetchrow_array;
 | 
			
		||||
                            }
 | 
			
		||||
                            else { # Must be a root category
 | 
			
		||||
                                $father_id = 0;
 | 
			
		||||
                            }
 | 
			
		||||
                            $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                            $cat_map{$_} = $ins_id;
 | 
			
		||||
                            $cat_id = $ins_id;
 | 
			
		||||
                            $missing_cats++;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        warning("Invalid category `$cat_name' for link $$row[0] (ID: $id, line $.). Link skipped"),next unless defined $cat_id;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                next LINK unless defined $cat_id;
 | 
			
		||||
                my $username;
 | 
			
		||||
                $user_count_sth->execute($contact_email) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
                if ($user_count_sth->fetchrow_arrayref()->[0]) { # This e-mail address already exists
 | 
			
		||||
                    $user_mod_sth->execute($contact_name, 'Yes', $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                    $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                    $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
                }
 | 
			
		||||
                elsif ($contact_email) {
 | 
			
		||||
                    $user_ins_sth->execute(($contact_email) x 2, (defined $contact_name ? $contact_name : ""), 'Yes') or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Registered')': ".$user_ins_sth->errstr);
 | 
			
		||||
                    $username = $contact_email;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                    $username = 'admin';
 | 
			
		||||
                }
 | 
			
		||||
                if ($insert_link_sth->execute($id,$username,'No',$date,$date,@$row)) {
 | 
			
		||||
                    $cat_links_sth->execute($id,$cat_id) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                    $num_of_links[$cat_id]++;
 | 
			
		||||
 | 
			
		||||
                    import_print "$links_imported\n" unless ++$links_imported % 500;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    $Links_counter-- unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals'): ".$insert_link_sth->errstr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            import_print "$links_imported records from 'Validate' imported.\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "$missing_cats categories have been created due to missing categories for links\n" if $missing_cats;
 | 
			
		||||
 | 
			
		||||
        for (grep $num_of_links[$_], 0..$#num_of_links) {
 | 
			
		||||
            $num_links_sth->execute($num_of_links[$_],$_) or warning "Unable to execute query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$num_links_sth->errstr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    $e_dbh->disconnect;
 | 
			
		||||
    import_print "\nNOTE: You must run Rebuild Cat. tree, Repair Tables, and Rebuild Search after performing an import!\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 4 options: a glob ref containing an opened filehandle, a table name, a
 | 
			
		||||
# hash ref, a scalar delimiter, and (optionally) an array of fields to return.
 | 
			
		||||
# The table name should be 'Links', 'CatRelations', 'Category', or 'Sessions'.
 | 
			
		||||
# If you give it the fields, it will come back with an array (or array ref) of
 | 
			
		||||
# the values for those fields in the order specified.
 | 
			
		||||
# Otherwise, it will return a hash ref (or hash in list context) of the fields
 | 
			
		||||
# in column => value format.
 | 
			
		||||
#
 | 
			
		||||
# Call it as %rec = get_rec(\*FH, $table_name, \@db_cols, $delimiter, \@fields);
 | 
			
		||||
# You can, if you prefer, also make the delimiter a scalar reference.
 | 
			
		||||
# @db_cols should be the @db_cols from Links 1.x.
 | 
			
		||||
sub get_rec {
 | 
			
		||||
    defined wantarray or return; # Don't bother doing anything in void context
 | 
			
		||||
    my $fh = shift;
 | 
			
		||||
    my $table_name = shift;
 | 
			
		||||
    my $db_cols = shift;
 | 
			
		||||
    my $delimiter = ref $_[0] eq 'SCALAR' ? ${shift()} : shift;
 | 
			
		||||
    my ($fields,@fields,%fields);
 | 
			
		||||
    if (@_) {
 | 
			
		||||
        $fields = 1;
 | 
			
		||||
        @fields = ref $_[0] eq 'ARRAY' ? @{shift()} : @_;
 | 
			
		||||
        %fields = map { ($_ => 1) } @fields;
 | 
			
		||||
    }
 | 
			
		||||
    defined fileno($fh) or critical "Interal error: File handle passed to get_rec() is not an opened file";
 | 
			
		||||
 | 
			
		||||
    local $/ = "\n";
 | 
			
		||||
    my $line;
 | 
			
		||||
    until (defined $line) {
 | 
			
		||||
        $line = <$fh>;
 | 
			
		||||
        return unless defined $line; # Catch the end of the file.
 | 
			
		||||
        chomp $line;
 | 
			
		||||
        $line ||= undef; # skip blanks
 | 
			
		||||
    }
 | 
			
		||||
    my $i = 0;
 | 
			
		||||
    my @rec = split /\Q$delimiter/, $line, -1;
 | 
			
		||||
    my %rec;
 | 
			
		||||
    for (@rec) {
 | 
			
		||||
        s/``/\n/g;
 | 
			
		||||
        s/~~/|/g;
 | 
			
		||||
        $_ = undef if $_ eq 'NULL';
 | 
			
		||||
    }
 | 
			
		||||
    for (0..$#rec) {
 | 
			
		||||
        if (defined $db_cols->[$_] and (!$fields or $fields{$db_cols->[$_]})) { # Skip "extra" and unwanted records
 | 
			
		||||
            $rec{$db_cols->[$_]} = $rec[$_];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ($table_name eq 'Links') {
 | 
			
		||||
        $rec{Category} =~ y/_/ / if $rec{Category};
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($table_name eq 'Category') {
 | 
			
		||||
        $rec{Name} =~ y/_/ / if $rec{Name};
 | 
			
		||||
        $rec{Related} =~ y/_/ / if $rec{Related};
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $fields or return wantarray ? %rec : \%rec;
 | 
			
		||||
    my @ret = map $rec{$_}, @fields;
 | 
			
		||||
    return wantarray ? @ret : \@ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Converts a date. Returns false if the date is invalid.
 | 
			
		||||
sub convert_date ($) {
 | 
			
		||||
    my $in = shift;
 | 
			
		||||
    my ($day, $mon, $year) = split /-/, $in, 3;
 | 
			
		||||
    my %months = qw(Jan 01 Feb 02 Mar 03 Apr 04 May 05 Jun 06 Jul 07 Aug 08 Sep 09 Oct 10 Nov 11 Dec 12);
 | 
			
		||||
# Any extra fields needed should be set like this:
 | 
			
		||||
#    $months{Okt} = "10";
 | 
			
		||||
#    $months{Mai} = "05";
 | 
			
		||||
#    $months{Dez} = "12";
 | 
			
		||||
#
 | 
			
		||||
    $day = sprintf "%02d", $day;
 | 
			
		||||
    $year = sprintf "%04d", $year;
 | 
			
		||||
    if ($year and $months{$mon} and $day) {
 | 
			
		||||
        return sprintf("%04d-$months{$mon}-%02d", $year, $day);
 | 
			
		||||
    } else {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Returns a random password of random length (20-25 characters).
 | 
			
		||||
sub random_pass () {
 | 
			
		||||
    my @chars = ('a'..'z','A'..'Z',0..9,qw a _ [ ] { } ` ' " ! @ ^ * ( ) - _ = + : ; . / \ a,'#',',');
 | 
			
		||||
    my $pass = join '', map { $chars[rand @chars] } 0..(20+rand(5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"True or not true? That is the question."
 | 
			
		||||
							
								
								
									
										814
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/L2S2.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										814
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/L2S2.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,814 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#	Website  : http://gossamer-threads.com/
 | 
			
		||||
#	Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#	Revision : $Id: L2S2.pm,v 1.39 2005/04/16 02:11:50 brewt 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::Import::L2S2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my ($have_email_db,$have_validate_db);
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $e_prefix = $DB->prefix;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    local (*LINKS,*CATS,*EMAIL,$@,$!,*VALIDATE);
 | 
			
		||||
    my $did = do {
 | 
			
		||||
        package Links2::Def::Category; # Avoid namespace pollution
 | 
			
		||||
        do "$$opt{source}/category.def";
 | 
			
		||||
    };
 | 
			
		||||
    !$did and $@ and critical "Cannot parse $$opt{source}/category.def: $@";
 | 
			
		||||
    !$did and $! and critical "Cannot open $$opt{source}/category.def: $!";
 | 
			
		||||
    open CATS, "<$$opt{source}/data/categories.db" or critical "Unable to open $$opt{source}/data/categories.db: $!";
 | 
			
		||||
    $did = do {
 | 
			
		||||
        package Links2::Def::Links;
 | 
			
		||||
        do "$$opt{source}/links.def";
 | 
			
		||||
    };
 | 
			
		||||
    !$did and $@ and critical "Cannot parse $$opt{source}/links.def: $@";
 | 
			
		||||
    !$did and $! and critical "Cannot open $$opt{source}/links.def: $!";
 | 
			
		||||
    open LINKS, "<$$opt{source}/data/links.db" or critical "Unable to open $$opt{source}/data/links.db: $!";
 | 
			
		||||
    if (open VALIDATE, "<$$opt{source}/data/validate.db") {
 | 
			
		||||
        $have_validate_db = 1;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        warning "Could not open $$opt{source}/data/validate.db: $!. Non-validated links will not be imported.";
 | 
			
		||||
    }
 | 
			
		||||
    if (open EMAIL, "$$opt{source}/data/email.db") {
 | 
			
		||||
        $have_email_db = 1;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        warning "Could not open $$opt{source}/data/email.db: $!. No newsletter users will be imported.";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %e_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name FatherID Full_Name Description Meta_Description Meta_Keywords Header Footer Category_Template Number_of_Links Has_New_Links Has_Changed_Links Newest_Link Timestmp Payment_Mode/},
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL LinkOwner Add_Date Mod_Date Description Contact_Name Contact_Email Hits isNew isChanged isPopular isValidated Rating Votes Status Date_Checked Timestmp ExpiryDate ExpiryCounted ExpiryNotify/},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %e_non_standard_cols;
 | 
			
		||||
    for my $table (keys %e_standard_cols) {
 | 
			
		||||
        my %cols = $DB->table($table)->cols;
 | 
			
		||||
        for (grep !$e_standard_cols{$table}{$_}, keys %cols) {
 | 
			
		||||
            $e_non_standard_cols{$table}{$_} = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %i_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name Description Related Header Footer/,'Meta Description','Meta Keywords' },
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL Date Category Description Hits isNew isPopular Rating Votes ReceiveMail/,'Contact Name','Contact Email'}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %i_non_standard_cols;
 | 
			
		||||
    $i_non_standard_cols{Links} = { map { !$i_standard_cols{Links}{$_} ? ($_ => 1) : () } keys %Links2::Def::Links::db_def };
 | 
			
		||||
    $i_non_standard_cols{Category} = { map { !$i_standard_cols{Category}{$_} ? ($_ => 1) : () } keys %Links2::Def::Category::db_def };
 | 
			
		||||
 | 
			
		||||
    my $alt_categories = delete $i_non_standard_cols{Links}{AltCategories};
 | 
			
		||||
 | 
			
		||||
    my $Links_counter;
 | 
			
		||||
    my $Category_counter;
 | 
			
		||||
    my $odbc = 0;
 | 
			
		||||
    if ($DB->table('Links')->{connect}->{driver} eq 'ODBC') {
 | 
			
		||||
        $odbc = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($$opt{clear_tables}) {
 | 
			
		||||
    # Delete everything from all tables, EXCEPT for the `admin' user from the Users table
 | 
			
		||||
        $e_dbh->do("DELETE FROM ${e_prefix}Users WHERE Username <> 'admin'") or critical "Unable to delete all existing users: ".$e_dbh->errstr;
 | 
			
		||||
        for (qw/Links Category CatLinks CatRelations Category_Score_List
 | 
			
		||||
            Category_Word_List ClickTrack Editors EmailMailings EmailTemplates
 | 
			
		||||
            Links_Score_List Links_Word_List MailingIndex MailingList
 | 
			
		||||
            MailingListIndex Sessions Verify/) {
 | 
			
		||||
            $e_dbh->do("DELETE FROM $e_prefix$_");
 | 
			
		||||
        }
 | 
			
		||||
        unless ($$opt{straight_import}) {
 | 
			
		||||
            $Links_counter = $Category_counter = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        my $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Links") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$sth->errstr;
 | 
			
		||||
        $Links_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
 | 
			
		||||
        $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$sth->errstr;
 | 
			
		||||
        $Category_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
# Subscribe users - these users receive the newsletter.
 | 
			
		||||
    if ($have_email_db) {
 | 
			
		||||
        my $count_users = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?");
 | 
			
		||||
        my $add_user = $e_dbh->prepare("INSERT INTO ${e_prefix}Users (Name, Username, Password, Email, ReceiveMail) VALUES (?, ?, ?, ?, 'Yes')");
 | 
			
		||||
        my $give_newsletter = $e_dbh->prepare("UPDATE ${e_prefix}Users SET ReceiveMail = 'Yes' WHERE Email = ?");
 | 
			
		||||
 | 
			
		||||
        my $sub_imported = 0;
 | 
			
		||||
        import_print "\nImporting Subscribe users (newsletter receivers) ...\n";
 | 
			
		||||
        while (<EMAIL>) {
 | 
			
		||||
            chomp;
 | 
			
		||||
            my ($email,$name) = split /\|/;
 | 
			
		||||
            $name ||= "";
 | 
			
		||||
            $count_users->execute($email) or warning("Unable to count users with email $email: ".$count_users->errstr), next;
 | 
			
		||||
            if ($count_users->fetchrow_array) {
 | 
			
		||||
                $give_newsletter->execute($email) or warning("Unable to set ReceiveMail = 'Yes' for user with e-mail $email: ".$give_newsletter->errstr),--$sub_imported;
 | 
			
		||||
            }
 | 
			
		||||
            else { # User doesn't already exist
 | 
			
		||||
                $add_user->execute($name, $email, random_pass(), $email) or warning("Unable to insert user $email: ".$add_user->errstr),--$sub_imported;
 | 
			
		||||
            }
 | 
			
		||||
            import_print "$sub_imported\n" unless ++$sub_imported % 500;
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$sub_imported Subscribed users imported.\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Categories
 | 
			
		||||
    my %cat_map; # $cat_map{name} = new_id
 | 
			
		||||
    my @num_of_links; # $num_of_links[category_id] = (the number of links in that category)
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        my @cat_get_cols = ('ID','Name','Related',       'Description','Meta Description','Meta Keywords','Header','Footer');
 | 
			
		||||
        my $cat_ins_cols = "(ID, Name, FatherID, Full_Name, Description, Meta_Description, Meta_Keywords, Header, Footer";
 | 
			
		||||
        my $cat_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        # Build up extra fields that exist in both old and new Category tables
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Category"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Category}{$_}) {
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                push @cat_get_cols, $_;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Category.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Category"}{$_}, keys %{$i_non_standard_cols{Category}}) {
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                if (/\W/) {
 | 
			
		||||
                    critical "Custom import column `Category.$_' cannot be imported because is is not a valid column name. You will need to rename the column name in the def file and in any relevant templates to a new name consisting only of letters, numbers, and the _ character.";
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                mild_warning("Custom import column `Category.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Category");
 | 
			
		||||
                my @def = @{$Links2::Def::Category::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'ALPHA' and $def[3] > 255) ? 'TEXT' : 'CHAR'),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ()),
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                push @cat_get_cols, $_;
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Category"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Category.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $cat_ins_cols .= ")";
 | 
			
		||||
        $cat_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
        my $add_cat_relation = $e_dbh->prepare("INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
        my $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_ins_sth = $odbc
 | 
			
		||||
            ? ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals': ".$e_dbh->errstr))
 | 
			
		||||
            : ($e_dbh->prepare("INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $cat_ins_simple_sth = $odbc
 | 
			
		||||
            ? ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr))
 | 
			
		||||
            : ($e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $get_id_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            my ($no_warning) = (
 | 
			
		||||
                $Links2::Def::Category::db_delim,
 | 
			
		||||
                $Links2::Def::Links::db_delim
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        my @cat_relations;
 | 
			
		||||
 | 
			
		||||
        my $cat_imported = 0;
 | 
			
		||||
        import_print "\nImporting Categories ...\n";
 | 
			
		||||
        my @cat_data;
 | 
			
		||||
        while (my $row = get_rec(\*CATS,'Category',\%Links2::Def::Category::db_def,\$Links2::Def::Category::db_delim,\@cat_get_cols)) {
 | 
			
		||||
            push @cat_data, $row if ref $row eq 'ARRAY';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @cat_data = sort { $a->[0] cmp $b->[0] } @cat_data;
 | 
			
		||||
 | 
			
		||||
        my @missing_cats;
 | 
			
		||||
        my %missing_cats;
 | 
			
		||||
        for my $row (@cat_data) {
 | 
			
		||||
            $row = [@$row];
 | 
			
		||||
            my $old_id = shift @$row;
 | 
			
		||||
            my $new_id = $$opt{straight_import} ? $old_id : ++$Category_counter;
 | 
			
		||||
            my ($name) = (my $full_name = shift @$row) =~ m[([^/]*)\Z];
 | 
			
		||||
            unless (defined $name and length $name) {
 | 
			
		||||
                $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                warning "Cannot insert Category $full_name because it is an invalid name";
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
            my ($father_full_name) = $full_name =~ m[\A(.*)/];
 | 
			
		||||
            my $father_id;
 | 
			
		||||
            if (not defined $father_full_name) {
 | 
			
		||||
                $father_id = 0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $get_id_sth->execute($father_full_name) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_id_sth->errstr;
 | 
			
		||||
                if (my $ar = $get_id_sth->fetchrow_arrayref()) {
 | 
			
		||||
                    $father_id = $ar->[0] || 0;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    my $ins_pos = @missing_cats;
 | 
			
		||||
                    if ($$opt{create_missing_categories}) {
 | 
			
		||||
                        unless ($missing_cats{$father_full_name}++) {
 | 
			
		||||
                            splice @missing_cats, $ins_pos, 0, $father_full_name;
 | 
			
		||||
                            mild_warning "$father_full_name is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                            my $fn = $father_full_name;
 | 
			
		||||
                            while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                                $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                                if ($count_cats_sth->fetchrow_array or $missing_cats{$fn}++) { # It exists
 | 
			
		||||
                                    $count_cats_sth->finish;
 | 
			
		||||
                                    last;
 | 
			
		||||
                                }
 | 
			
		||||
                                else {
 | 
			
		||||
                                    splice @missing_cats, $ins_pos, 0, $fn;
 | 
			
		||||
                                    mild_warning "$fn is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                                    $count_cats_sth->finish;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            mild_warning "$father_full_name is also needed for category $full_name and is already in the queue to be created.";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        warning "No father row found for $full_name! This may be a serious error as $full_name should probably have a father category";
 | 
			
		||||
                    }
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
                $get_id_sth->finish;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $cat_relations[$new_id] = shift @$row; # This has to be dealt with later.
 | 
			
		||||
 | 
			
		||||
            if ($$opt{data_integrity}) {
 | 
			
		||||
                $count_cats_sth->execute($full_name) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                unless ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                    unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                        $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                        warning "Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr;
 | 
			
		||||
                        $count_cats_sth->finish;
 | 
			
		||||
                        next;
 | 
			
		||||
                    }
 | 
			
		||||
                    import_print "$cat_imported\n" unless ++$cat_imported % 500;
 | 
			
		||||
                    $cat_map{$full_name} = $new_id;
 | 
			
		||||
                    $num_of_links[$new_id] = 0;
 | 
			
		||||
                    $count_cats_sth->finish;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    mild_warning("Duplicate category found ($full_name) and skipped");
 | 
			
		||||
                    $count_cats_sth->finish;
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            elsif (!$cat_map{$full_name}) {
 | 
			
		||||
                unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr);
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                import_print "$cat_imported\n" unless ++$cat_imported % 500;
 | 
			
		||||
                $cat_map{$full_name} = $new_id;
 | 
			
		||||
                $num_of_links[$new_id] = 0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                mild_warning("Duplicate category found ($full_name) and skipped");
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        my $missing_cats;
 | 
			
		||||
        if ($$opt{create_missing_categories} and @missing_cats) {
 | 
			
		||||
            my $counter = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category");
 | 
			
		||||
            $counter->execute();
 | 
			
		||||
            my $ins_id = $counter->fetchrow_array();
 | 
			
		||||
            my $update_sub_cats = $e_dbh->prepare("UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?': ".$e_dbh->errstr;
 | 
			
		||||
            for (@missing_cats) {
 | 
			
		||||
                if ($cat_map{$_}) { # Already exists
 | 
			
		||||
                    $update_sub_cats->execute($cat_map{$_},"$_/%","$_/%/%") or critical "Unable to execute query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? and Full_Name NOT LIKE ?': ".$update_sub_cats->errstr;
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                my ($name) = m[([^/]*)\Z];
 | 
			
		||||
                my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                my $father_id;
 | 
			
		||||
                if ($father_full and exists $cat_map{$father_full}) {
 | 
			
		||||
                    $father_id = $cat_map{$father_full};
 | 
			
		||||
                }
 | 
			
		||||
                elsif ($father_full) {
 | 
			
		||||
                    $get_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_id_sth->errstr;
 | 
			
		||||
                    $father_id = $get_id_sth->fetchrow_array;
 | 
			
		||||
                }
 | 
			
		||||
                else { # Must be a category of root
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
                $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                $cat_map{$_} = $ins_id;
 | 
			
		||||
                $update_sub_cats->execute($ins_id,"$_/%","$_/%/%") or critical "Unable to execute query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? and Full_Name NOT LIKE ?': ".$update_sub_cats->errstr;
 | 
			
		||||
                $missing_cats++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "$cat_imported Categories imported";
 | 
			
		||||
        import_print ", $missing_cats missing categories created" if $missing_cats;
 | 
			
		||||
        import_print ".\n";
 | 
			
		||||
 | 
			
		||||
# Category Relations
 | 
			
		||||
        import_print "\nImporting Category Relations ...\n";
 | 
			
		||||
        my $cat_rel_imported = 0;
 | 
			
		||||
        for my $cat_id (0..$#cat_relations) {
 | 
			
		||||
            next unless defined $cat_relations[$cat_id];
 | 
			
		||||
            my @cats = split /\Q$Links2::Def::Category::db_delim/, $cat_relations[$cat_id];
 | 
			
		||||
            for (@cats) {
 | 
			
		||||
                $get_id_sth->execute($_) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ? <- $_': ".$get_id_sth->errstr;
 | 
			
		||||
                my $rel_id = $get_id_sth->fetchrow_array;
 | 
			
		||||
                if (defined $rel_id) {
 | 
			
		||||
                    unless ($add_cat_relation->execute($cat_id,$rel_id)) {
 | 
			
		||||
                        warning "Unable to execute query `INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)': ".$add_cat_relation->errstr;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        import_print "$cat_rel_imported\n" unless ++$cat_rel_imported % 500;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    warning "Unable to add category relation for category with ID $cat_id and `$_'. Reason: Category `$_' not found in database.";
 | 
			
		||||
                }
 | 
			
		||||
                $get_id_sth->finish;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$cat_rel_imported Category Relations imported.\n";
 | 
			
		||||
    }
 | 
			
		||||
# Links
 | 
			
		||||
    {
 | 
			
		||||
        my @links_get_cols = ('ID','Category','Date','Contact Name','Contact Email','ReceiveMail',       qw/Title  URL  Description  Hits  isNew  isPopular  Rating  Votes/);
 | 
			
		||||
        my $links_ins_cols = "(ID, LinkOwner, isValidated, Add_Date, Mod_Date, Contact_Name, Contact_Email, Title, URL, Description, Hits, isNew, isPopular, Rating, Votes";
 | 
			
		||||
        my $links_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Links"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Links}{$_}) {
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                push @links_get_cols, $_;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Links.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Links"}{$_}, keys %{$i_non_standard_cols{Links}}) {
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Links.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Links");
 | 
			
		||||
                my @def = @{$Links2::Def::Links::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'ALPHA' and $def[3] > 255) ? 'TEXT' : 'CHAR'),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ())
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                push @links_get_cols, $_;
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Links"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Links.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $links_ins_cols .= ")";
 | 
			
		||||
        $links_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
        unshift @links_get_cols, "AltCategories" if $alt_categories;
 | 
			
		||||
 | 
			
		||||
        my $user_ins_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Users (Password, Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_links_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$e_dbh->errstr);
 | 
			
		||||
        my $insert_link_sth = $odbc
 | 
			
		||||
            ? ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Links ON; INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals': ".$e_dbh->errstr))
 | 
			
		||||
            : ($e_dbh->prepare("INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        my $user_count_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $username_sth = $e_dbh->prepare("SELECT Username FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT Username FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        # What other than the Name and ReceiveMail can be updated here?
 | 
			
		||||
        my $user_mod_sth = $e_dbh->prepare("UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $num_links_sth = $e_dbh->prepare("UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my ($count_cats_sth,$get_cat_id_sth,$cat_ins_simple_sth);
 | 
			
		||||
        my $ins_id;
 | 
			
		||||
        if ($$opt{create_missing_categories}) {
 | 
			
		||||
            $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
            $get_cat_id_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
            $cat_ins_simple_sth = $odbc
 | 
			
		||||
                ? ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr)
 | 
			
		||||
                : ($e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr);
 | 
			
		||||
            my $counter = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category");
 | 
			
		||||
            $counter->execute();
 | 
			
		||||
            $ins_id = $counter->fetchrow_array();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "\nImporting Links ...\n";
 | 
			
		||||
        my $links_imported = 0;
 | 
			
		||||
        my $missing_cats = 0;
 | 
			
		||||
        my @more_needed; # This will hold any missing categories (such as A/B in A/B/C)
 | 
			
		||||
  LINK: while (my $row = get_rec(\*LINKS,'Links',\%Links2::Def::Links::db_def,\$Links2::Def::Links::db_delim,\@links_get_cols)) {
 | 
			
		||||
            $row = [@$row]; # Remove aliasing
 | 
			
		||||
            my $alt_cats;
 | 
			
		||||
            $alt_cats = shift @$row if $alt_categories;
 | 
			
		||||
            my ($id, $cat_name, $date, $contact_name, $contact_email, $receive_mail) = splice @$row,0,6;
 | 
			
		||||
            unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
            $date = convert_date($date) or warning("Invalid date for link with ID $id. Link skipped."),next;
 | 
			
		||||
            $id = ++$Links_counter unless $$opt{straight_import};
 | 
			
		||||
            my @category_alternates;
 | 
			
		||||
            if ($alt_categories) {
 | 
			
		||||
                @category_alternates = split /\Q$Links2::Def::Links::db_delim/, $alt_cats;
 | 
			
		||||
                for (@category_alternates) { y/_/ / }
 | 
			
		||||
                my %dups;
 | 
			
		||||
                # Get rid of duplicates
 | 
			
		||||
                @category_alternates = grep !$dups{$_}++, @category_alternates;
 | 
			
		||||
            }
 | 
			
		||||
            my @cats = ($cat_name,@category_alternates);
 | 
			
		||||
            my @cat_ids = @cat_map{@cats};
 | 
			
		||||
            my $bad_cats = 0;
 | 
			
		||||
            for my $j (0..$#cats) {
 | 
			
		||||
                my $cat_id = $cat_ids[$j];
 | 
			
		||||
                my $cat_name = $cats[$j];
 | 
			
		||||
                unless (defined $cat_id) {
 | 
			
		||||
                    if ($$opt{create_missing_categories} and $cat_name) {
 | 
			
		||||
                        my @needed = my $fn = $cat_name;
 | 
			
		||||
                        while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                            $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                            if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                                $count_cats_sth->finish;
 | 
			
		||||
                                last;
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                $count_cats_sth->finish;
 | 
			
		||||
                                unshift @needed, $fn;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        for (@needed) {
 | 
			
		||||
                            my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                            unless ($name) {
 | 
			
		||||
                                warning "Unable to create category $_ because it is an invalid name.";
 | 
			
		||||
                                $bad_cats++;
 | 
			
		||||
                                last;
 | 
			
		||||
                            }
 | 
			
		||||
                            mild_warning("Creating category $_ as it is needed by link ID $id");
 | 
			
		||||
                            my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                            my $father_id;
 | 
			
		||||
                            if ($father_full) {
 | 
			
		||||
                                $get_cat_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_cat_id_sth->errstr;
 | 
			
		||||
                                $father_id = $get_cat_id_sth->fetchrow_array;
 | 
			
		||||
                                $get_cat_id_sth->finish;
 | 
			
		||||
                            }
 | 
			
		||||
                            else { # Must be a root category
 | 
			
		||||
                                $father_id = 0;
 | 
			
		||||
                            }
 | 
			
		||||
                            $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                            $cat_map{$_} = $ins_id;
 | 
			
		||||
                            $cat_ids[$j] = $ins_id;
 | 
			
		||||
                            $missing_cats++;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        $bad_cats++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if ($bad_cats == @cat_ids) { # Between the category and the alternate categories, there has to be at least ONE good one.
 | 
			
		||||
                if (@cat_ids == 1) {
 | 
			
		||||
                    warning "Invalid category `$cat_ids[0]' for link $$row[0] (ID: $id, line $.). Link skipped";
 | 
			
		||||
                    next LINK;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    warning "No valid categories ($cat_name @category_alternates) for link $$row[0] (ID: $id, line $.). Link skipped";
 | 
			
		||||
                    next LINK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            my $username;
 | 
			
		||||
            $user_count_sth->execute($contact_email) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
            if ($user_count_sth->fetchrow_arrayref()->[0]) { # This e-mail address already exists
 | 
			
		||||
                $user_mod_sth->execute($contact_name, ($receive_mail eq 'Yes' ? 'Yes' : 'No'), $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
                $username_sth->finish;
 | 
			
		||||
            }
 | 
			
		||||
            elsif ($contact_email) {
 | 
			
		||||
                $user_ins_sth->execute('', ($contact_email) x 2, (defined $contact_name ? $contact_name : ""), ($receive_mail eq 'Yes' ? 'Yes' : 'No')) or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')': ".$user_ins_sth->errstr);
 | 
			
		||||
                $username = $contact_email;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                $username = 'admin';
 | 
			
		||||
            }
 | 
			
		||||
            $user_count_sth->finish;
 | 
			
		||||
            if ($insert_link_sth->execute($id,$username,'Yes',$date,$date,@$row)) {
 | 
			
		||||
                for my $cat_id (@cat_ids) {
 | 
			
		||||
                    $cat_links_sth->execute($id,$cat_id) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                    $num_of_links[$cat_id]++;
 | 
			
		||||
                }
 | 
			
		||||
                import_print "$links_imported\n" unless ++$links_imported % 500;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $Links_counter-- unless $$opt{straight_import};
 | 
			
		||||
                warning("Unable to insert link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals'): ".$insert_link_sth->errstr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$links_imported records from 'Links' imported.\n";
 | 
			
		||||
 | 
			
		||||
        if ($have_validate_db) {
 | 
			
		||||
            $links_imported = 0;
 | 
			
		||||
            import_print "Importing records from 'Validate'.\n";
 | 
			
		||||
 | 
			
		||||
      LINK: while(my $row = get_rec(\*VALIDATE,'Links',\%Links2::Def::Links::db_def,\$Links2::Def::Links::db_delim,\@links_get_cols)) {
 | 
			
		||||
                $row = [@$row]; # Remove aliasing
 | 
			
		||||
                my $alt_cats;
 | 
			
		||||
                $alt_cats = shift @$row if $alt_categories;
 | 
			
		||||
                my ($id, $cat_name, $date, $contact_name, $contact_email, $receive_mail) = splice @$row,0,6;
 | 
			
		||||
                unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
                $date = convert_date($date) or warning("Invalid date `$date' for link with ID $id. Link skipped."),next;
 | 
			
		||||
                $id = ++$Links_counter unless $$opt{straight_import};
 | 
			
		||||
 | 
			
		||||
                my @category_alternates;
 | 
			
		||||
                if ($alt_categories) {
 | 
			
		||||
                    @category_alternates = split /\Q$Links2::Def::Links::db_delim/, $alt_cats;
 | 
			
		||||
                }
 | 
			
		||||
                my @cats = ($cat_name,@category_alternates);
 | 
			
		||||
                my @cat_ids = @cat_map{@cats};
 | 
			
		||||
                my $bad_cats = 0;
 | 
			
		||||
                for (0..$#cats) {
 | 
			
		||||
                    my $cat_id = $cat_ids[$_];
 | 
			
		||||
                    my $cat_name = $cats[$_];
 | 
			
		||||
                    unless (defined $cat_id) {
 | 
			
		||||
                        if ($$opt{create_missing_categories} and $cat_name) {
 | 
			
		||||
                            my @needed = my $fn = $cat_name;
 | 
			
		||||
                            while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                                $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                                if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                                    $count_cats_sth->finish;
 | 
			
		||||
                                    last;
 | 
			
		||||
                                }
 | 
			
		||||
                                else {
 | 
			
		||||
                                    $count_cats_sth->finish;
 | 
			
		||||
                                    unshift @needed, $fn;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            for (@needed) {
 | 
			
		||||
                                my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                                unless ($name) {
 | 
			
		||||
                                    warning "Unable to create category $_ because it is an invalid name.";
 | 
			
		||||
                                    $bad_cats++;
 | 
			
		||||
                                    last;
 | 
			
		||||
                                }
 | 
			
		||||
                                mild_warning("Creating category $_ as it is needed by link ID $id");
 | 
			
		||||
                                my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                                my $father_id;
 | 
			
		||||
                                if ($father_full) {
 | 
			
		||||
                                    $get_cat_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$get_cat_id_sth->errstr;
 | 
			
		||||
                                    $father_id = $get_cat_id_sth->fetchrow_array;
 | 
			
		||||
                                    $get_cat_id_sth->finish;
 | 
			
		||||
                                }
 | 
			
		||||
                                else { # Must be a root category
 | 
			
		||||
                                    $father_id = 0;
 | 
			
		||||
                                }
 | 
			
		||||
                                $cat_ins_simple_sth->execute(++$ins_id,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                                $cat_map{$_} = $ins_id;
 | 
			
		||||
                                $cat_id = $ins_id;
 | 
			
		||||
                                $missing_cats++;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            $bad_cats++;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if ($bad_cats == @cat_ids) { # Between the category and the alternate categories, there has to be at least ONE good one.
 | 
			
		||||
                    if (@cat_ids == 1) {
 | 
			
		||||
                        warning "Invalid category `$cat_ids[0]' for link $$row[0] (ID: $id, line $.). Link skipped";
 | 
			
		||||
                        next LINK;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        warning "No valid categories ($cat_name @category_alternates) for link $$row[0] (ID: $id, line $.). Link skipped";
 | 
			
		||||
                        next LINK;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                my $username;
 | 
			
		||||
                $user_count_sth->execute($contact_email) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
                if ($user_count_sth->fetchrow_arrayref()->[0]) { # This e-mail address already exists
 | 
			
		||||
                    $user_mod_sth->execute($contact_name, ($receive_mail eq 'Yes' ? 'Yes' : 'No'), $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                    $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                    $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
                    $username_sth->finish;
 | 
			
		||||
                }
 | 
			
		||||
                elsif ($contact_email) {
 | 
			
		||||
                    $user_ins_sth->execute('', ($contact_email) x 2, (defined $contact_name ? $contact_name : ""), ($receive_mail eq 'Yes' ? 'Yes' : 'No')) or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')': ".$user_ins_sth->errstr);
 | 
			
		||||
                    $username = $contact_email;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                    $username = 'admin';
 | 
			
		||||
                }
 | 
			
		||||
                $user_count_sth->finish;
 | 
			
		||||
                if ($insert_link_sth->execute($id,$username,'No',$date,$date,@$row)) {
 | 
			
		||||
                    for my $cat_id (@cat_ids) {
 | 
			
		||||
                        next if (! defined $cat_id);
 | 
			
		||||
                        $cat_links_sth->execute($id,$cat_id) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                        $num_of_links[$cat_id]++;
 | 
			
		||||
                    }
 | 
			
		||||
                    import_print "$links_imported\n" unless ++$links_imported % 500;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    $Links_counter-- unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals'): ".$insert_link_sth->errstr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            import_print "$links_imported records from 'Validate' imported.\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "$missing_cats categories have been created due to missing categories for links\n" if $missing_cats;
 | 
			
		||||
 | 
			
		||||
        for (grep $num_of_links[$_], 0..$#num_of_links) {
 | 
			
		||||
            $num_links_sth->execute($num_of_links[$_],$_) or warning "Unable to execute query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$num_links_sth->errstr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    $e_dbh->disconnect;
 | 
			
		||||
    import_print "\nNOTE: You must run Rebuild Cat. tree, Repair Tables, and Rebuild Search after performing an import!\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 4 options: a glob ref containing an opened filehandle, a table name, a
 | 
			
		||||
# hash ref, a scalar delimiter, and (optionally) an array of fields to return.
 | 
			
		||||
# The table name should be 'Links', 'CatRelations', 'Category', or 'Sessions'.
 | 
			
		||||
# If you give it the fields, it will come back with an array (or array ref) of
 | 
			
		||||
# the values for those fields in the order specified.
 | 
			
		||||
# Otherwise, it will return a hash ref (or hash in list context) of the fields
 | 
			
		||||
# in column => value format.
 | 
			
		||||
#
 | 
			
		||||
# Call it as %rec = get_rec(\*FH, $table_name, \%db_def, $delimiter, \@fields);
 | 
			
		||||
# You can, if you prefer, also make the delimiter a scalar reference.
 | 
			
		||||
# The hash should be the %db_def used in Links 2.x.
 | 
			
		||||
sub get_rec {
 | 
			
		||||
    defined wantarray or return; # Don't bother doing anything in void context
 | 
			
		||||
    my $fh = shift;
 | 
			
		||||
    my $table_name = shift;
 | 
			
		||||
    my $db_def = shift;
 | 
			
		||||
    my $delimiter = ref $_[0] eq 'SCALAR' ? ${shift()} : shift;
 | 
			
		||||
    my ($fields,@fields,%fields);
 | 
			
		||||
    if (@_) {
 | 
			
		||||
        $fields = 1;
 | 
			
		||||
        @fields = ref $_[0] eq 'ARRAY' ? @{shift()} : @_;
 | 
			
		||||
        %fields = map { ($_ => 1) } @fields;
 | 
			
		||||
    }
 | 
			
		||||
    defined fileno($fh) or critical "Interal error: File handle passed to get_rec() is not an opened file";
 | 
			
		||||
 | 
			
		||||
    my @mapping = sort { $db_def->{$a}[0] <=> $db_def->{$b}[0] } keys %$db_def;
 | 
			
		||||
    local $/ = "\n";
 | 
			
		||||
    my $line;
 | 
			
		||||
    until (defined $line) {
 | 
			
		||||
        $line = <$fh>;
 | 
			
		||||
        return unless defined $line; # Catch the end of the file.
 | 
			
		||||
        chomp $line;
 | 
			
		||||
        $line ||= undef;
 | 
			
		||||
    }
 | 
			
		||||
    my $i = 0;
 | 
			
		||||
    my @rec = split /\Q$delimiter/, $line, -1;
 | 
			
		||||
    my %rec;
 | 
			
		||||
    for (@rec) {
 | 
			
		||||
        s/``/\n/g;
 | 
			
		||||
        s/~~/|/g;
 | 
			
		||||
        $_ = undef if $_ eq 'NULL';
 | 
			
		||||
    }
 | 
			
		||||
    for (0..$#rec) {
 | 
			
		||||
        if (defined $mapping[$_] and (!$fields or $fields{$mapping[$_]})) { # Skip "extra" and unwanted records
 | 
			
		||||
            $rec{$mapping[$_]} = $rec[$_];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ($table_name eq 'Links') {
 | 
			
		||||
        $rec{Category} =~ y/_/ / if $rec{Category};
 | 
			
		||||
        $rec{Hits} ||= 0 if exists $rec{Hits}; # Fix for Links 2 database having the Hits table removed
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($table_name eq 'Category') {
 | 
			
		||||
        $rec{Name} =~ y/_/ / if $rec{Name};
 | 
			
		||||
        $rec{Related} =~ y/_/ / if $rec{Related};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $fields or return wantarray ? %rec : \%rec;
 | 
			
		||||
    my @ret = map $rec{$_}, @fields;
 | 
			
		||||
    return wantarray ? @ret : \@ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Converts a date. Returns false if the date is invalid.
 | 
			
		||||
sub convert_date ($) {
 | 
			
		||||
    my $in = shift;
 | 
			
		||||
    my ($day, $mon, $year) = split /-/, $in, 3;
 | 
			
		||||
    my %months = qw(Jan 01 Feb 02 Mar 03 Apr 04 May 05 Jun 06 Jul 07 Aug 08 Sep 09 Oct 10 Nov 11 Dec 12);
 | 
			
		||||
# Any extra fields needed should be set like this:
 | 
			
		||||
#    $months{Okt} = "10";
 | 
			
		||||
#    $months{Mai} = "05";
 | 
			
		||||
#    $months{Dez} = "12";
 | 
			
		||||
#
 | 
			
		||||
    if ($year and $months{$mon} and $day) {
 | 
			
		||||
        return sprintf("%04d-$months{$mon}-%02d", $year, $day);
 | 
			
		||||
    } else {
 | 
			
		||||
        warning "Invalid date `$in' encountered.";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Returns a random password of random length (20-25 characters).
 | 
			
		||||
sub random_pass () {
 | 
			
		||||
    my @chars = ('a'..'z','A'..'Z',0..9,qw a _ [ ] { } ` ' " ! @ ^ * ( ) - _ = + : ; . / \ a,'#',',');
 | 
			
		||||
    my $pass = join '', map { $chars[rand @chars] } 0..(20+rand(5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"True or not true? That is the question."
 | 
			
		||||
							
								
								
									
										533
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/RDFS2.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										533
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/RDFS2.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,533 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#   Website  : http://gossamer-threads.com/
 | 
			
		||||
#   Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#   CVS Info : 087,071,086,086,085      
 | 
			
		||||
#   Revision : $Id: RDFS2.pm,v 1.20 2005/04/07 19:34:41 brewt 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::Import::RDFS2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use DBI;
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
use GT::RDF;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $e_prefix = $DB->prefix;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $Links_counter;
 | 
			
		||||
    my $Category_counter;
 | 
			
		||||
    my $odbc = 0;
 | 
			
		||||
    if (($DB->table('Links')->{connect}{driver} || "") eq "ODBC") {
 | 
			
		||||
        $odbc = 1;
 | 
			
		||||
# Set max read properties for DBI.
 | 
			
		||||
        $e_dbh->{LongReadLen} = 1000000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($$opt{clear_tables}) {
 | 
			
		||||
    # Delete everything from all tables, EXCEPT for the `admin' user from the Users table.
 | 
			
		||||
    # Also ignore --rdf-user if specified.
 | 
			
		||||
        if ($$opt{rdf_user}) {
 | 
			
		||||
            my $sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Username = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Username = ?': ".$e_dbh->errstr;
 | 
			
		||||
            $sth->execute($$opt{rdf_user}) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Username = ?': ".$sth->errstr;
 | 
			
		||||
            if ($sth->fetchrow_array) {
 | 
			
		||||
                $e_dbh->do("DELETE FROM ${e_prefix}Users WHERE Username <> 'admin' AND Username <> ".$e_dbh->quote($$opt{rdf_user}));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                critical "The rdf username that you specified ($$opt{rdf_user}) does not exist. Please create the user.";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $e_dbh->do("DELETE FROM ${e_prefix}Users WHERE Username <> 'admin'") or critical "Unable to delete all existing users: ".$e_dbh->errstr;
 | 
			
		||||
        }
 | 
			
		||||
        for (qw/Links Category CatLinks CatRelations Category_Score_List
 | 
			
		||||
            Category_Word_List ClickTrack Editors EmailMailings EmailTemplates
 | 
			
		||||
            Links_Score_List Links_Word_List MailingIndex MailingList
 | 
			
		||||
            MailingListIndex Verify/) {
 | 
			
		||||
            $e_dbh->do("DELETE FROM $e_prefix$_");
 | 
			
		||||
        }
 | 
			
		||||
        unless ($$opt{straight_import}) {
 | 
			
		||||
            $Links_counter = $Category_counter = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        my $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Links") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute() or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$sth->errstr;
 | 
			
		||||
        $Links_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
 | 
			
		||||
        $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute() or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$sth->errstr;
 | 
			
		||||
        $Category_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $gzip = $$opt{with_gzip};
 | 
			
		||||
    my $need_gz = -B $$opt{source}; # Tests if the file is binary.
 | 
			
		||||
 | 
			
		||||
    my $is_win = $^O =~ /win/i;
 | 
			
		||||
 | 
			
		||||
    my $gzip_filename = $is_win ? "gzip.exe" : "gzip";
 | 
			
		||||
 | 
			
		||||
    if (not $gzip and $need_gz) {
 | 
			
		||||
# Try to find gzip
 | 
			
		||||
        my $dir_sep = $is_win ? ";" : ":";
 | 
			
		||||
        my @locations = split /$dir_sep/, $ENV{PATH};
 | 
			
		||||
        for (@locations) {
 | 
			
		||||
            -x "$_/$gzip_filename" and $gzip = "$_/$gzip_filename", last;
 | 
			
		||||
        }
 | 
			
		||||
        $gzip or critical "\nUnable to locate gzip (Searched @locations). Please specify with --with-gzip=\"/path/to/gzip\"";
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($gzip and -d $gzip) {
 | 
			
		||||
        if (-x "$gzip/$gzip_filename") {
 | 
			
		||||
            $gzip = "$gzip/$gzip_filename";
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            critical "\nThe directory $gzip does not contain a valid gzip program";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ($need_gz) {
 | 
			
		||||
        -x $gzip or critical "\nUnable to find an executable gzip";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $rdf = \do { local *FH; *FH };
 | 
			
		||||
 | 
			
		||||
    if ($$opt{with_gzip} or $need_gz) {
 | 
			
		||||
        import_print "\nOpening uncompressed stream from gzip compressed file `$$opt{source}' ...\n";
 | 
			
		||||
        open $rdf, " $gzip -c -d $$opt{source} |" or critical "Unable to open `$gzip -c -d $$opt{source} |': $!";
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        import_print "\nOpening stream from non-compressed file `$$opt{source}' ...\n";
 | 
			
		||||
        open $rdf, "<$$opt{source}" or critical "Unable to open $$opt{source}: $!";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    import_print "Stream opened.\n";
 | 
			
		||||
# Do the import
 | 
			
		||||
    {
 | 
			
		||||
        my $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
        my $cat_id_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical "Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $cat_ins_sth = $odbc
 | 
			
		||||
            ? $e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID, Number_of_Links, Has_New_Links, Has_Changed_Links) VALUES (?, ?, ?, ?, 0, 'No', 'No')")
 | 
			
		||||
            : $e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID, Number_of_Links, Has_New_Links, Has_Changed_Links) VALUES (?, ?, ?, ?, 0, 'No', 'No')");
 | 
			
		||||
        $cat_ins_sth or critical "Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $sub_cats_sth = $e_dbh->prepare("UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?': ".$e_dbh->errstr;
 | 
			
		||||
        my $get_num_links_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}CatLinks WHERE CategoryID = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}CatLinks WHERE CategoryID = ?': ".$e_dbh->errstr;
 | 
			
		||||
        my $num_links_sth = $e_dbh->prepare("UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $insert_link_sth = $odbc
 | 
			
		||||
            ? $e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Links ON; INSERT INTO ${e_prefix}Links (ID, Title, URL, Add_Date, Mod_Date, Description, LinkOwner, Status, Votes, Rating, Hits) VALUES (?, ?, ?, ?, ?, ?, ".$e_dbh->quote($$opt{rdf_user} or "admin").",0,0,0,0)")
 | 
			
		||||
            : $e_dbh->prepare("INSERT INTO ${e_prefix}Links (ID, Title, URL, Add_Date, Mod_Date, Description, LinkOwner, Status, Votes, Rating, Hits) VALUES (?, ?, ?, ?, ?, ?, ".$e_dbh->quote($$opt{rdf_user} or "admin").",0,0,0,0)");
 | 
			
		||||
        $insert_link_sth or critical "Unable to prepare query `INSERT INTO ${e_prefix}Links (Title, URL, Add_Date, Mod_Date, Description, LinkOwner) VALUES (?, ?, ?, ?, ?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $link_exists_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Links, ${e_prefix}CatLinks WHERE URL = ? AND CategoryID = ? AND ID = LinkID") or critical "Unable to prepare query `SELECT * FROM Links, CatLinks WHERE URL = ? AND CategoryID = ? AND ID = LinkID': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $cat_links_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        my $count_links_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}CatLinks WHERE CategoryID = ?") or critical "Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}CatLinks WHERE CategoryID = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        import_print "\nImporting from $$opt{source}\n";
 | 
			
		||||
        my $links_imported = 0;
 | 
			
		||||
        my $cats_imported = 0;
 | 
			
		||||
        my %cat_needs_num; # $cat_needs_num{cat_id} = 1 if the category needs to have its Number_Of_Links updated
 | 
			
		||||
 | 
			
		||||
        my $base_cat = $$opt{rdf_destination};
 | 
			
		||||
        my $base_cat_id;
 | 
			
		||||
        if (defined $base_cat) {
 | 
			
		||||
            $base_cat =~ s|//+|/|g; # Remove doubled (and more) slashes
 | 
			
		||||
            $base_cat =~ s|^/+||; # Remove any leading slashes
 | 
			
		||||
            $base_cat =~ s|/+$||; # And any trailing ones
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $base_cat = "";
 | 
			
		||||
        }
 | 
			
		||||
        if (length $base_cat) {
 | 
			
		||||
            $count_cats_sth->execute($base_cat) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
            if ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                $cat_id_sth->execute($base_cat) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$cat_id_sth->errstr;
 | 
			
		||||
                $base_cat_id = $cat_id_sth->fetchrow_array;
 | 
			
		||||
            }
 | 
			
		||||
            else { # Category doesn't exist
 | 
			
		||||
                my @missing_cats = $base_cat;
 | 
			
		||||
                mild_warning "$base_cat does not exist and is being created";
 | 
			
		||||
                my $fn = $base_cat;
 | 
			
		||||
                while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                    $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                    if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                        last;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        unshift @missing_cats, $fn;
 | 
			
		||||
                        mild_warning "$fn is needed for base category $base_cat and does not exist. It will be created";
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                for (@missing_cats) {
 | 
			
		||||
                    my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                    my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                    my $father_id;
 | 
			
		||||
                    if ($father_full) {
 | 
			
		||||
                        $cat_id_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$cat_id_sth->errstr;
 | 
			
		||||
                        $father_id = $cat_id_sth->fetchrow_array;
 | 
			
		||||
                    }
 | 
			
		||||
                    else { # Must be the root category
 | 
			
		||||
                        $father_id = 0;
 | 
			
		||||
                    }
 | 
			
		||||
                    $cat_ins_sth->execute(++$Category_counter,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_sth->errstr;
 | 
			
		||||
                    $cats_imported++;
 | 
			
		||||
                    $sub_cats_sth->execute($Category_counter,"$_/%","$_/%/%") or critical "Unable to execute query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? and Full_Name NOT LIKE ?': ".$sub_cats_sth->errstr;
 | 
			
		||||
                }
 | 
			
		||||
                $base_cat_id = $Category_counter; # The last one inserted will be the category import base
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $base_cat_id = 0;
 | 
			
		||||
        }
 | 
			
		||||
        my $cat = $$opt{rdf_category};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -------------------------------------------------------------------
 | 
			
		||||
# Main code, get a parser object and start parsing!
 | 
			
		||||
#
 | 
			
		||||
# New for 2.2.0 - XML::Parser-based code, which should be significantly faster.
 | 
			
		||||
# It should, however, still be considered experimental.
 | 
			
		||||
#
 | 
			
		||||
        if ($$opt{xml_parser}) {
 | 
			
		||||
            require XML::Parser;
 | 
			
		||||
            my (%links, %want, %current, @in);
 | 
			
		||||
            my $last_status = -1;
 | 
			
		||||
            my $insert_cat = sub {
 | 
			
		||||
                my $cat_name = $current{category};
 | 
			
		||||
 | 
			
		||||
# If we are under ODBC we need to reset the sth handle to avoid a "Invalid Cursor State" error.
 | 
			
		||||
                $odbc and $count_cats_sth->finish;
 | 
			
		||||
 | 
			
		||||
# Check to make sure we haven't seen this category before
 | 
			
		||||
# Set $found to the category ID.
 | 
			
		||||
                $count_cats_sth->execute($cat_name) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                if ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                    $cat_id_sth->finish if ($odbc); # Need to reset cursor under odbc.
 | 
			
		||||
                    $cat_id_sth->execute($cat_name) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                    $current{cat_id} = $cat_id_sth->fetchrow_array;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    my ($father_name, $short_name) = $current{category} =~ m|(?:(.*)/)?([^/]+)$|;
 | 
			
		||||
                    my $father_id;
 | 
			
		||||
                    if ($father_name) {
 | 
			
		||||
                        $cat_id_sth->finish if ($odbc); # Need to reset cursor under odbc.
 | 
			
		||||
                        $cat_id_sth->execute($father_name) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                        $father_id = $cat_id_sth->fetchrow_array;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        $father_id = 0;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $cat_ins_sth->execute(++$Category_counter, $short_name, $current{category}, $father_id) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                    $cats_imported++;
 | 
			
		||||
                    $current{cat_id} = $Category_counter;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                for my $link (keys %links) {
 | 
			
		||||
# Either append, or insert new link.
 | 
			
		||||
                    if ($$opt{rdf_update}) {
 | 
			
		||||
                        $link_exists_sth->execute($link, $current{cat_id}) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                        next if $link_exists_sth->fetchrow;
 | 
			
		||||
                    }
 | 
			
		||||
# Title can only be 100 characters (ODBC fatals about data that is too long).
 | 
			
		||||
                    my $title = substr($links{$link}->{title} || $link, 0, 100);
 | 
			
		||||
                    $insert_link_sth->execute(++$Links_counter, $title, $link, $$opt{rdf_add_date}, $$opt{rdf_add_date}, $links{$link}->{description} || "") or critical "Execute: $DBI::errstr";
 | 
			
		||||
                    $cat_links_sth->execute($Links_counter, $current{cat_id}) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                    $cat_needs_num{$current{cat_id}} = 1;
 | 
			
		||||
                    $links_imported++;
 | 
			
		||||
                }
 | 
			
		||||
                %links = ();
 | 
			
		||||
                return scalar keys %links;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            my $parser = XML::Parser->new(
 | 
			
		||||
                Handlers => {
 | 
			
		||||
                    Start => sub {
 | 
			
		||||
                        my ($parser, $tag, %attr) = @_;
 | 
			
		||||
                        if ($tag eq 'Topic') {
 | 
			
		||||
                            {
 | 
			
		||||
                                my $disp_topic = $attr{'r:id'};
 | 
			
		||||
                                substr($disp_topic, 30) = '...' if length $disp_topic > 33;
 | 
			
		||||
                                my $padding = " " x (33 - length $disp_topic);
 | 
			
		||||
                                $disp_topic = "(L:$links_imported, C:$cats_imported) $disp_topic$padding";
 | 
			
		||||
                                import_print("\r$disp_topic");
 | 
			
		||||
                            }
 | 
			
		||||
                            if ($current{category}) {
 | 
			
		||||
                                my $cat_count = $insert_cat->();
 | 
			
		||||
                                import_print "$cat_count       ";
 | 
			
		||||
                            }
 | 
			
		||||
                            my $dmoz_cat = $attr{'r:id'};
 | 
			
		||||
                            if ($dmoz_cat =~ /^\Q$cat\E(.*)/) {
 | 
			
		||||
                                my $topic = $base_cat . '/' . $1;
 | 
			
		||||
                                $topic =~ s|/{2,}|/|g;
 | 
			
		||||
                                $topic =~ s|^/||;
 | 
			
		||||
                                $topic =~ s|/$||;
 | 
			
		||||
                                $topic =~ y|_| |;
 | 
			
		||||
                                $current{category} = $topic;
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                delete $current{category};
 | 
			
		||||
                                import_print "skipping";
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($tag eq 'link' and $in[-1] eq 'Topic' and $current{category} and $attr{'r:resource'}) {
 | 
			
		||||
                            $links{$attr{'r:resource'}} = {};
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($tag eq 'ExternalPage' and $current{category} and $attr{about}) {
 | 
			
		||||
                            $current{ExternalPage} = $attr{about};
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($tag eq 'd:Title' and $in[-1] eq 'ExternalPage' and $current{ExternalPage}) {
 | 
			
		||||
                            $want{title} = \$links{$current{ExternalPage}}->{title};
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($tag eq 'd:Description' and $in[-1] eq 'ExternalPage' and $current{ExternalPage}) {
 | 
			
		||||
                            $want{description} = \$links{$current{ExternalPage}}->{description};
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        push @in, $tag;
 | 
			
		||||
                    },
 | 
			
		||||
                    End => sub {
 | 
			
		||||
                        my ($parser, $tag) = @_;
 | 
			
		||||
                        pop @in;
 | 
			
		||||
                        if ($tag eq 'd:Description') {
 | 
			
		||||
                            delete $want{description};
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($tag eq 'd:Title') {
 | 
			
		||||
                            delete $want{title};
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    Char => sub {
 | 
			
		||||
                        my ($parser, $text) = @_;
 | 
			
		||||
                        if ($want{title}) {
 | 
			
		||||
                            ${$want{title}} = $text;
 | 
			
		||||
                        }
 | 
			
		||||
                        elsif ($want{description}) {
 | 
			
		||||
                            ${$want{description}} = $text;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            $parser->parse($rdf, ProtocolEncoding => 'ISO-8859-1');
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            my $parse = GT::RDF->new (io => $rdf);
 | 
			
		||||
            my ($found, $was_found, %links);
 | 
			
		||||
            my $cat_count   = 0;
 | 
			
		||||
            my $first       = 0;
 | 
			
		||||
 | 
			
		||||
            while ($parse->parse) {
 | 
			
		||||
 | 
			
		||||
# Either we have a topic, external page or unknown. 
 | 
			
		||||
                if ($parse->{name} eq 'Topic') {
 | 
			
		||||
 | 
			
		||||
# Add extra links that did not have external page info.
 | 
			
		||||
                    if (defined $found) {
 | 
			
		||||
                        foreach my $link (keys %links) {
 | 
			
		||||
                            if ($$opt{rdf_update}) {
 | 
			
		||||
                                $link_exists_sth->execute($parse->{attribs}{about},$found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                unless ($link_exists_sth->fetchrow_array) {
 | 
			
		||||
                                    $insert_link_sth->execute(++$Links_counter, $link, $link, $$opt{rdf_add_date}, $$opt{rdf_add_date}, "") or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                    $cat_links_sth->execute($Links_counter, $found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                    $cat_needs_num{$found} = 1;
 | 
			
		||||
                                    $links_imported++;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                $insert_link_sth->execute(++$Links_counter, $link, $link, $$opt{rdf_add_date}, $$opt{rdf_add_date}, "") or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                $cat_links_sth->execute($Links_counter, $found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                $cat_needs_num{$found} = 1;
 | 
			
		||||
                                $links_imported++;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        import_print "$cat_count       ";
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        import_print "skipping" if $first++;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
# Clear out our links hash, and set found to undef.
 | 
			
		||||
                    $cat_count  = 0;
 | 
			
		||||
                    %links      = ();
 | 
			
		||||
                    $was_found  = $found;
 | 
			
		||||
                    $found      = undef;
 | 
			
		||||
 | 
			
		||||
# We've finished a topic, start a new one.
 | 
			
		||||
                    my $dmoz_cat = $parse->{attribs}{'r:id'};
 | 
			
		||||
                    if ($dmoz_cat =~ /^\Q$cat\E(.*)/) {
 | 
			
		||||
                        my $topic = $base_cat . '/' . $1;
 | 
			
		||||
                        $topic =~ s|//+|/|g;
 | 
			
		||||
                        $topic =~ s|^/||;
 | 
			
		||||
                        $topic =~ s|/$||;
 | 
			
		||||
                        $topic =~ s|_| |g;
 | 
			
		||||
                        if ($topic) {
 | 
			
		||||
 | 
			
		||||
# If we are under ODBC we need to reset the sth handle to avoid a "Invalid Cursor State" error.
 | 
			
		||||
                            $odbc and ($count_cats_sth->finish);
 | 
			
		||||
 | 
			
		||||
# Check to make sure we haven't seen this category before
 | 
			
		||||
# Set $found to the category ID.
 | 
			
		||||
                            $count_cats_sth->execute($topic) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                            if ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                                $cat_id_sth->finish if ($odbc); # Need to reset cursor under odbc.
 | 
			
		||||
                                $cat_id_sth->execute($topic) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                $found = $cat_id_sth->fetchrow_array;
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                my ($short_name) = $topic =~ m|([^/]+)$|;
 | 
			
		||||
                                my ($father_name) = $topic =~ m|(.*)/|;
 | 
			
		||||
                                my $father_id;
 | 
			
		||||
                                if ($father_name) {
 | 
			
		||||
                                    $cat_id_sth->finish if ($odbc); # Need to reset cursor under odbc.
 | 
			
		||||
                                    $cat_id_sth->execute($father_name) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                    $father_id = $cat_id_sth->fetchrow_array;
 | 
			
		||||
                                }
 | 
			
		||||
                                else {
 | 
			
		||||
                                    $father_id = 0;
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                $cat_ins_sth->execute(++$Category_counter, $short_name, $topic, $father_id) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                                $cats_imported++;
 | 
			
		||||
                                $found = $Category_counter;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    {
 | 
			
		||||
                        my $disp_topic = $parse->{attribs}{'r:id'};
 | 
			
		||||
                        substr($disp_topic, 30) = '...' if length $disp_topic > 33;
 | 
			
		||||
                        my $padding = " " x (33 - length $disp_topic);
 | 
			
		||||
                        $disp_topic = "(L:$links_imported, C:$cats_imported) $disp_topic$padding";
 | 
			
		||||
                        import_print("\r$disp_topic");
 | 
			
		||||
                    }
 | 
			
		||||
                    if (defined $found) {
 | 
			
		||||
                        for (@{$parse->{tags}}) {
 | 
			
		||||
                            next unless ($_->{attribs}{'r:resource'});
 | 
			
		||||
                            $links{$_->{attribs}{'r:resource'}} = 1;
 | 
			
		||||
                            $cat_count++;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        return 1 if $was_found;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                elsif (defined ($found) and $parse->{name} eq 'ExternalPage') {
 | 
			
		||||
 | 
			
		||||
# Remove from our simple link list.
 | 
			
		||||
                    delete $links{$parse->{attribs}{about}};
 | 
			
		||||
 | 
			
		||||
# Insert with description or title if it does not exist and we are not overwritting
 | 
			
		||||
                    my ($title, $desc);
 | 
			
		||||
                    for (@{$parse->{tags}}) {
 | 
			
		||||
                        if ($_->{name} eq 'd:Title' and $_->{data}) { $title = $_->{data} }
 | 
			
		||||
                        elsif ($_->{name} eq 'd:Description' and $_->{data}) { $desc = $_->{data} }
 | 
			
		||||
                    }
 | 
			
		||||
                    $title ||= $parse->{attribs}{about};
 | 
			
		||||
                    $desc  ||= '';
 | 
			
		||||
 | 
			
		||||
# Either append, or insert new link.
 | 
			
		||||
                    if ($$opt{rdf_update}) {
 | 
			
		||||
                        $link_exists_sth->execute ($parse->{attribs}{about},$found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                        unless ($link_exists_sth->fetchrow_array) {
 | 
			
		||||
# Title can only be 100 characters (ODBC fatals about data that is too long).
 | 
			
		||||
                            $title = substr($title, 0, 100);
 | 
			
		||||
                            $insert_link_sth->execute(++$Links_counter, $title, $parse->{attribs}{about}, $$opt{rdf_add_date}, $$opt{rdf_add_date}, $desc) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                            $cat_links_sth->execute($Links_counter, $found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                            $cat_needs_num{$found} = 1;
 | 
			
		||||
                            $links_imported++;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
# Title can only be 100 characters (ODBC fatals about data that is too long).
 | 
			
		||||
                        $title = substr($title, 0, 100);
 | 
			
		||||
                        $insert_link_sth->execute(++$Links_counter, $title, $parse->{attribs}{about}, $$opt{rdf_add_date}, $$opt{rdf_add_date}, $desc) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                        $cat_links_sth->execute($Links_counter, $found) or critical "Execute: $DBI::errstr";
 | 
			
		||||
                        $cat_needs_num{$found} = 1;
 | 
			
		||||
                        $links_imported++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                elsif (defined $found) {
 | 
			
		||||
                    require GT::Dumper;
 | 
			
		||||
                    critical "STRANGE TAG: " . GT::Dumper::Dumper($parse) . "\n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
# Now we have to go through the categories to update each one's Number_Of_Links
 | 
			
		||||
        for (keys %cat_needs_num) {
 | 
			
		||||
            $count_links_sth->execute($_) or critical "Unable to count links for Category ID $_: ".$count_links_sth->errstr;
 | 
			
		||||
            my $links = $count_links_sth->fetchrow_array;
 | 
			
		||||
            $count_links_sth->finish if ($odbc);
 | 
			
		||||
            $num_links_sth->execute($links,$_) or critical "Unable to update number of links for Category ID $_: ".$num_links_sth->errstr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    import_print "\nNOTE: You must run Rebuild Cat. tree, Repair Tables, and Rebuild Search after performing an import!\n";
 | 
			
		||||
 | 
			
		||||
    $e_dbh->disconnect;
 | 
			
		||||
    1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
'"I am lying," said the man. Was he?';
 | 
			
		||||
							
								
								
									
										802
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/S1S2.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										802
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/S1S2.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,802 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#   Website  : http://gossamer-threads.com/
 | 
			
		||||
#   Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#   CVS Info : 087,071,086,086,085      
 | 
			
		||||
#   Revision : $Id: S1S2.pm,v 1.32 2005/04/16 02:11:50 brewt 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::Import::S1S2;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use DBI;
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (qw/Category Links CategoryRelations CategoryAlternates Validate Users Subscribe/) {
 | 
			
		||||
        local ($!,$@);
 | 
			
		||||
        my $did = do "$$opt{source}/$_.def";
 | 
			
		||||
        critical "Error parsing file $$opt{source}/$_: $@" if !$did and $@;
 | 
			
		||||
        critical "Error reading file $$opt{source}/$_: $!" if !$did and $!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
# Check that all necessary databases have been loaded from the def files
 | 
			
		||||
    my $DEBUG_counter = 0;
 | 
			
		||||
    for ($Links::DBSQL::Category::db_driver,
 | 
			
		||||
         $Links::DBSQL::Category::db_user,
 | 
			
		||||
         $Links::DBSQL::Category::db_pass,
 | 
			
		||||
         $Links::DBSQL::Category::db_host,
 | 
			
		||||
         $Links::DBSQL::Category::db_table,
 | 
			
		||||
         $Links::DBSQL::Category::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (Category)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::Links::db_driver,
 | 
			
		||||
         $Links::DBSQL::Links::db_user,
 | 
			
		||||
         $Links::DBSQL::Links::db_pass,
 | 
			
		||||
         $Links::DBSQL::Links::db_host,
 | 
			
		||||
         $Links::DBSQL::Links::db_table,
 | 
			
		||||
         $Links::DBSQL::Links::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (Links)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::CategoryRelations::db_driver,
 | 
			
		||||
         $Links::DBSQL::CategoryRelations::db_user,
 | 
			
		||||
         $Links::DBSQL::CategoryRelations::db_pass,
 | 
			
		||||
         $Links::DBSQL::CategoryRelations::db_host,
 | 
			
		||||
         $Links::DBSQL::CategoryRelations::db_table,
 | 
			
		||||
         $Links::DBSQL::CategoryRelations::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (CategoryRelations)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::CategoryAlternates::db_driver,
 | 
			
		||||
         $Links::DBSQL::CategoryAlternates::db_user,
 | 
			
		||||
         $Links::DBSQL::CategoryAlternates::db_pass,
 | 
			
		||||
         $Links::DBSQL::CategoryAlternates::db_host,
 | 
			
		||||
         $Links::DBSQL::CategoryAlternates::db_table,
 | 
			
		||||
         $Links::DBSQL::CategoryAlternates::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (CategoryAlternates)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::Validate::db_driver,
 | 
			
		||||
         $Links::DBSQL::Validate::db_user,
 | 
			
		||||
         $Links::DBSQL::Validate::db_pass,
 | 
			
		||||
         $Links::DBSQL::Validate::db_host,
 | 
			
		||||
         $Links::DBSQL::Validate::db_table,
 | 
			
		||||
         $Links::DBSQL::Validate::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (Validate)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::Users::db_driver,
 | 
			
		||||
         $Links::DBSQL::Users::db_user,
 | 
			
		||||
         $Links::DBSQL::Users::db_pass,
 | 
			
		||||
         $Links::DBSQL::Users::db_host,
 | 
			
		||||
         $Links::DBSQL::Users::db_table,
 | 
			
		||||
         $Links::DBSQL::Users::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (Users)";
 | 
			
		||||
    }
 | 
			
		||||
    for ($Links::DBSQL::Subscribe::db_driver,
 | 
			
		||||
         $Links::DBSQL::Subscribe::db_user,
 | 
			
		||||
         $Links::DBSQL::Subscribe::db_pass,
 | 
			
		||||
         $Links::DBSQL::Subscribe::db_host,
 | 
			
		||||
         $Links::DBSQL::Subscribe::db_table,
 | 
			
		||||
         $Links::DBSQL::Subscribe::db_name) {
 | 
			
		||||
        defined $_ or critical "The source def files did not load correctly (Subscribe)";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %i_dbh;
 | 
			
		||||
    my $i_dbi_opts = { AutoCommit => 1, RaiseError => 0, PrintError => 0 };
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        my ($no_warning) = ($Links::DBSQL::Category::db_port,
 | 
			
		||||
                            $Links::DBSQL::Links::db_port,
 | 
			
		||||
                            $Links::DBSQL::Validate::db_port,
 | 
			
		||||
                            $Links::DBSQL::Users::db_port,
 | 
			
		||||
                            $Links::DBSQL::Subscribe::db_port,
 | 
			
		||||
                            $Links::DBSQL::CategoryRelations::db_port,
 | 
			
		||||
                            $Links::DBSQL::CategoryAlternates::db_port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (   ['Category', $Links::DBSQL::Category::db_name, $Links::DBSQL::Category::db_driver, $Links::DBSQL::Category::db_host, $Links::DBSQL::Category::db_port, $Links::DBSQL::Category::db_user, $Links::DBSQL::Category::db_pass ],
 | 
			
		||||
            ['Links',    $Links::DBSQL::Links::db_name,    $Links::DBSQL::Links::db_driver,    $Links::DBSQL::Links::db_host,    $Links::DBSQL::Links::db_port,    $Links::DBSQL::Links::db_user,    $Links::DBSQL::Links::db_pass    ],
 | 
			
		||||
            ['Validate', $Links::DBSQL::Validate::db_name, $Links::DBSQL::Validate::db_driver, $Links::DBSQL::Validate::db_host, $Links::DBSQL::Validate::db_port, $Links::DBSQL::Validate::db_user, $Links::DBSQL::Validate::db_pass ],
 | 
			
		||||
            ['Users',    $Links::DBSQL::Users::db_name,    $Links::DBSQL::Users::db_driver,    $Links::DBSQL::Users::db_host,    $Links::DBSQL::Users::db_port,    $Links::DBSQL::Users::db_user,    $Links::DBSQL::Users::db_pass    ],
 | 
			
		||||
            ['Subscribe',$Links::DBSQL::Subscribe::db_name,$Links::DBSQL::Subscribe::db_driver,$Links::DBSQL::Subscribe::db_host,$Links::DBSQL::Subscribe::db_port,$Links::DBSQL::Subscribe::db_user,$Links::DBSQL::Subscribe::db_pass],
 | 
			
		||||
            ['CategoryRelations',$Links::DBSQL::CategoryRelations::db_name,$Links::DBSQL::CategoryRelations::db_driver,$Links::DBSQL::CategoryRelations::db_host,$Links::DBSQL::CategoryRelations::db_port,$Links::DBSQL::CategoryRelations::db_user,$Links::DBSQL::CategoryRelations::db_pass],
 | 
			
		||||
            ['CategoryAlternates',$Links::DBSQL::CategoryAlternates::db_name,$Links::DBSQL::CategoryAlternates::db_driver,$Links::DBSQL::CategoryAlternates::db_host,$Links::DBSQL::CategoryAlternates::db_port,$Links::DBSQL::CategoryAlternates::db_user,$Links::DBSQL::CategoryAlternates::db_pass]) {
 | 
			
		||||
        my $driver = $$_[2] || "mysql";
 | 
			
		||||
        critical "The source def files did not load correctly (no \$db_name set for $$_[0] table)" unless $$_[1];
 | 
			
		||||
        next if exists $i_dbh{$$_[1]};
 | 
			
		||||
        my $dsn = "DBI:$driver:$$_[1]";
 | 
			
		||||
        if ($driver eq "mysql") {
 | 
			
		||||
            if ($$_[3]) {
 | 
			
		||||
                $dsn .= ":$$_[3]";
 | 
			
		||||
                if ($$_[4]) {
 | 
			
		||||
                    $dsn .= ":$$_[4]";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $i_dbh{$$_[1]} = DBI->connect($dsn,@$_[5,6],$i_dbi_opts) or critical("Couldn't connect to source $$_[0] db: ".$DBI::errstr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{destination}, subclass => 0);
 | 
			
		||||
    my $e_prefix = $DB->prefix;
 | 
			
		||||
    my $e_dbh;
 | 
			
		||||
    {
 | 
			
		||||
        my $table = $DB->table("Links");
 | 
			
		||||
        $table->connect();
 | 
			
		||||
        $e_dbh = $table->{driver}->connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %e_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name FatherID Full_Name Description Meta_Description Meta_Keywords Header Footer Category_Template Number_of_Links Has_New_Links Has_Changed_Links Newest_Link Timestmp Payment_Mode/},
 | 
			
		||||
        Users    => { map { ($_ => 1) } qw/Username Password Email Name Validation Status ReceiveMail/},
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL LinkOwner Add_Date Mod_Date Description Contact_Name Contact_Email Hits isNew isChanged isPopular isValidated Rating Votes Status Date_Checked Timestmp ExpiryDate ExpiryCounted ExpiryNotify/},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %e_non_standard_cols;
 | 
			
		||||
    for my $table (keys %e_standard_cols) {
 | 
			
		||||
        my %cols = $DB->table($table)->cols;
 | 
			
		||||
        for (grep !$e_standard_cols{$table}{$_}, keys %cols) {
 | 
			
		||||
            $e_non_standard_cols{$table}{$_} = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %i_standard_cols = (
 | 
			
		||||
        Category => { map { ($_ => 1) } qw/ID Name Description Meta_Description Meta_Keywords Header Footer Number_of_Links Has_New_Links Has_Changed_Links Newest_Link/},
 | 
			
		||||
        Users    => { map { ($_ => 1) } qw/Username Password Email Validation Status/},
 | 
			
		||||
        Links    => { map { ($_ => 1) } qw/ID Title URL Add_Date Mod_Date CategoryID Description Contact_Name Contact_Email Hits isNew isChanged isPopular Rating Votes ReceiveMail Status Date_Checked/},
 | 
			
		||||
        Validate => { map { ($_ => 1) } qw/ID Title URL Add_Date Mod_Date CategoryID Description Contact_Name Contact_Email Hits isNew isChanged isPopular Rating Votes ReceiveMail Status Date_Checked LinkID Mode/},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    my %i_non_standard_cols;
 | 
			
		||||
    $i_non_standard_cols{Category} = { map { !$i_standard_cols{Category}{$_} ? ($_ => 1) : () } keys %Links::DBSQL::Category::db_def } if keys %Links::DBSQL::Category::db_def;
 | 
			
		||||
    $i_non_standard_cols{Users} =    { map { !$i_standard_cols{Users}{$_}    ? ($_ => 1) : () } keys %Links::DBSQL::Users::db_def }    if keys %Links::DBSQL::Users::db_def;
 | 
			
		||||
    $i_non_standard_cols{Links} =    { map { !$i_standard_cols{Links}{$_}    ? ($_ => 1) : () } keys %Links::DBSQL::Links::db_def }    if keys %Links::DBSQL::Links::db_def;
 | 
			
		||||
    $i_non_standard_cols{Validate} = { map { !$i_standard_cols{Validate}{$_} ? ($_ => 1) : () } keys %Links::DBSQL::Validate::db_def } if keys %Links::DBSQL::Validate::db_def;
 | 
			
		||||
 | 
			
		||||
    my $Links_counter;
 | 
			
		||||
    my $Category_counter;
 | 
			
		||||
 | 
			
		||||
    my $odbc = 0;
 | 
			
		||||
    if ($DB->table('Links')->{connect}->{driver} eq 'ODBC') {
 | 
			
		||||
        $odbc = 1;
 | 
			
		||||
        $i_dbh{$Links::DBSQL::Links::db_name}->{LongReadLen} = 1000000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($$opt{clear_tables}) {
 | 
			
		||||
    # Delete everything from all tables, EXCEPT for the `admin' user from the Users table
 | 
			
		||||
        $e_dbh->do("DELETE FROM ${e_prefix}Users WHERE Username <> 'admin'") or critical "Unable to delete all existing users: ".$e_dbh->errstr;
 | 
			
		||||
        for (qw/Links Category CatLinks CatRelations Category_Score_List
 | 
			
		||||
            Category_Word_List ClickTrack Editors EmailMailings EmailTemplates
 | 
			
		||||
            Links_Score_List Links_Word_List MailingIndex MailingList
 | 
			
		||||
            MailingListIndex Sessions Verify/) {
 | 
			
		||||
            $e_dbh->do("DELETE FROM $e_prefix$_");
 | 
			
		||||
        }
 | 
			
		||||
        unless ($$opt{straight_import}) {
 | 
			
		||||
            $Links_counter = $Category_counter = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        my $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Links") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$sth->errstr;
 | 
			
		||||
        $Links_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
 | 
			
		||||
        $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$e_dbh->errstr;
 | 
			
		||||
        $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Category': ".$sth->errstr;
 | 
			
		||||
        $Category_counter = $sth->fetchrow_array;
 | 
			
		||||
        $sth->finish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
# Users
 | 
			
		||||
    {
 | 
			
		||||
        my $get_cols = "Username, Password, Email, Validation, Status";
 | 
			
		||||
        my $ins_cols = "(Name, Username, Password, Email, Validation, Status";
 | 
			
		||||
        my $ins_vals = "(?, ?, ?, ?, ?, ?";
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Users"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Users}{$_}) {
 | 
			
		||||
                $ins_cols .= ", $_";
 | 
			
		||||
                $ins_vals .= ", ?";
 | 
			
		||||
                $get_cols .= ", $_";
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Users.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for (grep +(not $e_standard_cols{"${e_prefix}Users"}{$_} and not $e_non_standard_cols{"${e_prefix}Users"}{$_}), keys %{$i_non_standard_cols{Users}}) {
 | 
			
		||||
            next if $e_non_standard_cols{"${e_prefix}Users"}{$_};
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Users.$_' had no destination equivelant. A column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Users");
 | 
			
		||||
                my @def = @{$Links::DBSQL::Users::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'CHAR' and $def[3] > 255) ? 'TEXT' : $def[1]),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ()),
 | 
			
		||||
                        ($def[7] ? (weight    => $def[7]) : ())
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $ins_cols .= ", $_";
 | 
			
		||||
                $ins_vals .= ", ?";
 | 
			
		||||
                $get_cols .= ", $_";
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Users"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Users.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $ins_cols .= ")";
 | 
			
		||||
        $ins_vals .= ")";
 | 
			
		||||
        my $sth = $i_dbh{$Links::DBSQL::Users::db_name}->prepare("SELECT $get_cols FROM $Links::DBSQL::Users::db_table") or critical("Unable to prepare query `SELECT $get_cols FROM $Links::DBSQL::Users::db_table': ".$i_dbh{$Links::DBSQL::Users::db_name}->errstr);
 | 
			
		||||
        $sth->execute() or critical("Unable to execute query `SELECT $get_cols FROM $Links::DBSQL::Users::db_table': ".$sth->errstr);
 | 
			
		||||
        my $ins_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Users $ins_cols VALUES $ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Users $ins_cols VALUES $ins_vals': ".$e_dbh->errstr);
 | 
			
		||||
        my $user_count_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $username_sth = $e_dbh->prepare("SELECT Username FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT Username FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        # What other than the Name and ReceiveMail can be updated here?
 | 
			
		||||
        my $user_mod_sth = $e_dbh->prepare("UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        while (my $row = $sth->fetchrow_arrayref) {
 | 
			
		||||
            $user_count_sth->execute($$row[2]) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
            if ($user_count_sth->fetchrow_array) { # This e-mail address already exists, so skip it
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
            $ins_sth->execute(@$row[0,0],($$row[1] or random_pass()),@$row[2..$#$row]) or warning("Unable to execute query `INSERT INTO ${e_prefix}Users $ins_cols VALUES $ins_vals' ($$row[0]): ".$ins_sth->errstr),next;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
# Subscribe users - these users receive the newsletter.
 | 
			
		||||
    {
 | 
			
		||||
        my $get_subscribers = $i_dbh{$Links::DBSQL::Subscribe::db_name}->prepare("SELECT Name, Email FROM $Links::DBSQL::Subscribe::db_table") or warning("Unable to prepare query `SELECT Name, Email FROM $Links::DBSQL::Subscribe::db_table': ".$i_dbh{$Links::DBSQL::Subscribe::db_name}->errstr);
 | 
			
		||||
        $get_subscribers->execute();
 | 
			
		||||
        my $count_users = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?");
 | 
			
		||||
        my $add_user = $e_dbh->prepare("INSERT INTO ${e_prefix}Users (Name, Username, Password, Email, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Yes', 'Registered')");
 | 
			
		||||
        my $give_newsletter = $e_dbh->prepare("UPDATE ReceiveMail = 'Yes' WHERE Email = ?");
 | 
			
		||||
 | 
			
		||||
        my $sub_imported = 0;
 | 
			
		||||
        import_print "\nImporting Subscribed users (users who receive the newsletter) ...\n";
 | 
			
		||||
        while (my $row = $get_subscribers->fetchrow_arrayref) {
 | 
			
		||||
# If we are under ODBC we need to reset the sth handle to avoid a "Invalid Cursor State" error.
 | 
			
		||||
            $odbc and ($count_users->finish);
 | 
			
		||||
            $count_users->execute($$row[1]) or warning("Unable to count users with email $$row[1]: ".$count_users->errstr), next;
 | 
			
		||||
            if ($count_users->fetchrow_array) {
 | 
			
		||||
                $give_newsletter->execute($$row[1]) or warning("Unable to set Newsletter = 'Yes' for user with e-mail $$row[1]: ".$give_newsletter->errstr),--$sub_imported;
 | 
			
		||||
            }
 | 
			
		||||
            else { # User doesn't already exist
 | 
			
		||||
                $add_user->execute($$row[0], $$row[1], random_pass(), $$row[1]) or warning("Unable to insert user $$row[1]: ".$add_user->errstr),--$sub_imported;
 | 
			
		||||
            }
 | 
			
		||||
            import_print "$sub_imported\n" unless ++$sub_imported % 500;
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$sub_imported Subscribed users imported.\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
# Everything else (in most cases including even more users)
 | 
			
		||||
    {
 | 
			
		||||
        # Category select statements
 | 
			
		||||
        my $cat_get_cols = "ID, Name, Description, Meta_Description, Meta_Keywords, " .
 | 
			
		||||
                "Header, Footer, Number_of_Links, Has_New_Links, Has_Changed_Links, Newest_Link";
 | 
			
		||||
        my $cat_ins_cols = "(ID, Name, FatherID, Full_Name, Description, Meta_Description, Meta_Keywords, " .
 | 
			
		||||
                "Header, Footer, Number_of_Links, Has_New_Links, Has_Changed_Links, Newest_Link";
 | 
			
		||||
        my $cat_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        # Links select statements
 | 
			
		||||
        my $links_get_cols = "ID, Contact_Name, Contact_Email, ReceiveMail, CategoryID, " .
 | 
			
		||||
                       "Title, URL, Add_Date, Mod_Date, Description, Hits, isNew, " .
 | 
			
		||||
                       "isChanged, isPopular, Rating, Votes, Status, Date_Checked";
 | 
			
		||||
        my $links_ins_cols = "(ID, LinkOwner, isValidated, Contact_Name, Contact_Email, " .
 | 
			
		||||
                       "Title, URL, Add_Date, Mod_Date, Description, Hits, isNew, " .
 | 
			
		||||
                       "isChanged, isPopular, Rating, Votes, Status, Date_Checked";
 | 
			
		||||
        my $links_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        # Validate select statements
 | 
			
		||||
        my $validate_get_cols = "ID, Contact_Name, Contact_Email, ReceiveMail, CategoryID, " .
 | 
			
		||||
                       "Title, URL, Add_Date, Mod_Date, Description, Hits, isNew, " .
 | 
			
		||||
                       "isChanged, isPopular, Rating, Votes, Status, Date_Checked";
 | 
			
		||||
        my $validate_ins_cols = "(ID, LinkOwner, isValidated, Contact_Name, Contact_Email, " .
 | 
			
		||||
                       "Title, URL, Add_Date, Mod_Date, Description, Hits, isNew, " .
 | 
			
		||||
                       "isChanged, isPopular, Rating, Votes, Status, Date_Checked";
 | 
			
		||||
        my $validate_ins_vals = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?";
 | 
			
		||||
 | 
			
		||||
        # Build up extra fields that exist in both old and new Category tables
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Category"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Category}{$_}) {
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                $cat_get_cols .= ", $_";
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Category.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Category"}{$_}, keys %{$i_non_standard_cols{Category}}) {
 | 
			
		||||
            next if $e_non_standard_cols{"${e_prefix}Category"}{$_};
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Category.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Category");
 | 
			
		||||
                my @def = @{$Links::DBSQL::Category::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'CHAR' and $def[3] > 255) ? 'TEXT' : $def[1]),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ()),
 | 
			
		||||
                        ($def[7] ? (weight    => $def[7]) : ())
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $cat_ins_cols .= ", $_";
 | 
			
		||||
                $cat_ins_vals .= ", ?";
 | 
			
		||||
                $cat_get_cols .= ", $_";
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Category"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Category.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $cat_ins_cols .= ")";
 | 
			
		||||
        $cat_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Links"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Links}{$_}) {
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                $links_get_cols .= ", $_";
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Links.$_' has no equivelant import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Links"}{$_}, keys %{$i_non_standard_cols{Links}}) {
 | 
			
		||||
            next if $e_non_standard_cols{"${e_prefix}Links"}{$_};
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Links.$_' had no destination equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Links");
 | 
			
		||||
                my @def = @{$Links::DBSQL::Links::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'CHAR' and $def[3] > 255) ? 'TEXT' : $def[1]),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ()),
 | 
			
		||||
                        ($def[7] ? (weight    => $def[7]) : ())
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $links_ins_cols .= ", $_";
 | 
			
		||||
                $links_ins_vals .= ", ?";
 | 
			
		||||
                $links_get_cols .= ", $_";
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Links"}{$_} = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Links.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $links_ins_cols .= ")";
 | 
			
		||||
        $links_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        for (keys %{$e_non_standard_cols{"${e_prefix}Links"}}) {
 | 
			
		||||
            if ($i_non_standard_cols{Validate}{$_}) {
 | 
			
		||||
                $validate_ins_cols .= ", $_";
 | 
			
		||||
                $validate_ins_vals .= ", ?";
 | 
			
		||||
                $validate_get_cols .= ", $_";
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mild_warning("Custom destination column `${e_prefix}Links.$_' has no equivelant Validate import column. It will contain the default values for the column");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (grep !$e_non_standard_cols{"${e_prefix}Links"}{$_}, keys %{$i_non_standard_cols{Validate}}) {
 | 
			
		||||
            next if $e_non_standard_cols{"${e_prefix}Links"}{$_};
 | 
			
		||||
            if ($opt->{create_columns}) {
 | 
			
		||||
                mild_warning("Custom import column `Validate.$_' had no destination Links equivelant. A destination column will be created");
 | 
			
		||||
                my $editor = $DB->editor("Links");
 | 
			
		||||
                my @def = @{$Links::DBSQL::Validate::db_def{$_}};
 | 
			
		||||
                $editor->add_col(
 | 
			
		||||
                    $_,
 | 
			
		||||
                    {
 | 
			
		||||
                        type                  => ((uc $def[1] eq 'CHAR' and $def[3] > 255) ? 'TEXT' : $def[1]),
 | 
			
		||||
                        ($def[2] ? (form_size => ((index($def[2],"x") > -1) ? [split(/x/,$def[2],2)] : $def[2])) : ()),
 | 
			
		||||
                        size                  => $def[3],
 | 
			
		||||
                        ($def[4] ? (not_null  => 1)       : ()),
 | 
			
		||||
                        ($def[5] ? (default   => $def[5]) : ()),
 | 
			
		||||
                        ($def[6] ? (regex     => $def[6]) : ()),
 | 
			
		||||
                        ($def[7] ? (weight    => $def[7]) : ())
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                $validate_ins_cols .= ", $_";
 | 
			
		||||
                $validate_ins_vals .= ", ?";
 | 
			
		||||
                $validate_get_cols .= ", $_";
 | 
			
		||||
 | 
			
		||||
                $e_non_standard_cols{"${e_prefix}Links"}{$_} = 1;
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                warning("Custom import column `Validate.$_' has no destination equivelant. It will be ignored");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $validate_ins_cols .= ")";
 | 
			
		||||
        $validate_ins_vals .= ")";
 | 
			
		||||
 | 
			
		||||
        my $cat_sth = $i_dbh{$Links::DBSQL::Category::db_name}->prepare("SELECT $cat_get_cols FROM $Links::DBSQL::Category::db_table ORDER BY Name") or critical("Unable to prepare query `SELECT $cat_get_cols FROM $Links::DBSQL::Category::db_table ORDER BY Name': ".$i_dbh{$Links::DBSQL::Category::db_name}->errstr);
 | 
			
		||||
        $cat_sth->execute() or critical("Unable to execute query `SELECT $cat_get_cols FROM $Links::DBSQL::Category::db_table ORDER BY Name': ".$cat_sth->errstr);
 | 
			
		||||
 | 
			
		||||
        my $get_cat_relations = $i_dbh{$Links::DBSQL::CategoryRelations::db_name}->prepare("SELECT CategoryID, RelatedID from $Links::DBSQL::CategoryRelations::db_table") or critical "Unable to prepare query `SELECT CategoryID, RelatedID from $Links::DBSQL::CategoryRelations::db_table': ".$i_dbh{$Links::DBSQL::CategoryRelations::db_name}->errstr;
 | 
			
		||||
        my $add_cat_relation = $e_dbh->prepare("INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)") or critical "Unable to prepare query `INSERT INTO ${e_prefix}CatRelations (CategoryID, RelatedID) VALUES (?, ?)': ".$e_dbh->errstr;
 | 
			
		||||
        my @cat_map; # $cat_map[old_id] = new_id; Don't need this with --straight-import enabled
 | 
			
		||||
 | 
			
		||||
        my $count_cats_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        my $get_cat_alts = $i_dbh{$Links::DBSQL::CategoryAlternates::db_name}->prepare("SELECT CategoryID FROM $Links::DBSQL::CategoryAlternates::db_table WHERE LinkID = ?") or critical "Unable to prepare query `SELECT * FROM $Links::DBSQL::CategoryAlternates::db_table WHERE LinkID = ?': ".$i_dbh{$Links::DBSQL::CategoryAlternates::db_name}->errstr;
 | 
			
		||||
 | 
			
		||||
        my $cat_ins_sth = $odbc ?
 | 
			
		||||
                                ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals': ".$e_dbh->errstr)) :
 | 
			
		||||
                                ($e_dbh->prepare("INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $cat_ins_simple_sth = $odbc ?
 | 
			
		||||
                                ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Category ON; INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr)) :
 | 
			
		||||
                                ($e_dbh->prepare("INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Category (ID, Name, Full_Name, FatherID) VALUES (?, ?, ?, ?)': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $user_ins_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}Users (Username, Email, Password, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, ?, 'Registered')': ".$e_dbh->errstr);
 | 
			
		||||
        my $cat_links_sth = $e_dbh->prepare("INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)") or critical("Unable to prepare query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$e_dbh->errstr);
 | 
			
		||||
        my $insert_link_sth = $odbc ?
 | 
			
		||||
                                ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Links ON; INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals': ".$e_dbh->errstr)) :
 | 
			
		||||
                                ($e_dbh->prepare("INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $insert_vlink_sth = $odbc ?
 | 
			
		||||
                                ($e_dbh->prepare("SET IDENTITY_INSERT ${e_prefix}Links ON; INSERT INTO ${e_prefix}Links $validate_ins_cols VALUES $validate_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $validate_ins_cols VALUES $validate_ins_vals': ".$e_dbh->errstr)) :
 | 
			
		||||
                                ($e_dbh->prepare("INSERT INTO ${e_prefix}Links $validate_ins_cols VALUES $validate_ins_vals") or critical("Unable to prepare query `INSERT INTO ${e_prefix}Links $validate_ins_cols VALUES $validate_ins_vals': ".$e_dbh->errstr));
 | 
			
		||||
 | 
			
		||||
        my $father_sth = $e_dbh->prepare("SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?") or critical("Unable to prepare query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        my $get_links_sth = $i_dbh{$Links::DBSQL::Links::db_name}->prepare("SELECT $links_get_cols FROM $Links::DBSQL::Links::db_table WHERE CategoryID = ?") or critical("Unable to prepare query `SELECT $links_get_cols FROM $Links::DBSQL::Links::db_table WHERE CategoryID = ?': ".$i_dbh{$Links::DBSQL::Links::db_name}->errstr);
 | 
			
		||||
        my $get_vlinks_sth = $i_dbh{$Links::DBSQL::Validate::db_name}->prepare("SELECT $validate_get_cols FROM $Links::DBSQL::Validate::db_table WHERE CategoryID = ?") or critical("Unable to prepare query `SELECT $validate_get_cols FROM $Links::DBSQL::Validate::db_table WHERE CategoryID = ?': ".$i_dbh{$Links::DBSQL::Validate::db_name}->errstr);
 | 
			
		||||
 | 
			
		||||
        my $user_count_sth = $e_dbh->prepare("SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
        my $username_sth = $e_dbh->prepare("SELECT Username FROM ${e_prefix}Users WHERE Email = ?") or critical("Unable to prepare query `SELECT Username FROM ${e_prefix}Users WHERE Email = ?': ".$e_dbh->errstr);
 | 
			
		||||
 | 
			
		||||
        # What other than the Name and ReceiveMail can be updated here?
 | 
			
		||||
        my $user_mod_sth = $e_dbh->prepare("UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$e_dbh->errstr;
 | 
			
		||||
        my $num_links_sth = $e_dbh->prepare("UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$e_dbh->errstr;
 | 
			
		||||
 | 
			
		||||
        import_print "\nImporting Categories and Links ...\n";
 | 
			
		||||
        my $links_imported = 0;
 | 
			
		||||
        my $cats_imported = 0;
 | 
			
		||||
        my @missing_cats; # contains the Full_Name's of missing categories.
 | 
			
		||||
        my %missing_cats; # contains Full_name => true for missing categories.
 | 
			
		||||
 | 
			
		||||
# Have to go through hoops here as ODBC can only run one sth at a time.
 | 
			
		||||
        my $sub;
 | 
			
		||||
        if ($odbc) {
 | 
			
		||||
            my $results = $cat_sth->fetchall_arrayref;
 | 
			
		||||
            $cat_sth->finish;
 | 
			
		||||
            import_print "\n\tImporting ", scalar @$results, " categories ..\n";
 | 
			
		||||
            $sub = sub { return shift @$results; }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $sub = sub { $cat_sth->fetchrow_arrayref; }
 | 
			
		||||
        }
 | 
			
		||||
        while(my $row = $sub->()) {
 | 
			
		||||
            $row = [@$row];
 | 
			
		||||
            my $old_id = shift @$row;
 | 
			
		||||
            my $new_id = $$opt{straight_import} ? $old_id : ++$Category_counter;
 | 
			
		||||
            my ($name) = (my $full_name = shift @$row) =~ m[([^/]*)\Z];
 | 
			
		||||
            unless (defined $name and length $name) {
 | 
			
		||||
                $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                warning "Cannot insert Category $full_name because it is an invalid name";
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
            my ($father_full_name) = $full_name =~ m[\A(.*)/];
 | 
			
		||||
            my $father_id;
 | 
			
		||||
            if (not defined $father_full_name) {
 | 
			
		||||
                $father_id = 0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $odbc and $father_sth->finish;
 | 
			
		||||
                $father_sth->execute($father_full_name) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$father_sth->errstr;
 | 
			
		||||
                if (my $ar = $father_sth->fetchrow_arrayref()) {
 | 
			
		||||
                    $father_id = $ar->[0] || 0;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    if ($$opt{create_missing_categories}) {
 | 
			
		||||
                        if ($missing_cats{$father_full_name}++) {
 | 
			
		||||
                            mild_warning "$father_full_name is needed for category $full_name and is already in the list of categories to be created";
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            my $ins_pos = @missing_cats;
 | 
			
		||||
                            splice @missing_cats, $ins_pos, 0, $father_full_name;
 | 
			
		||||
                            mild_warning "$father_full_name is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                            my $fn = $father_full_name;
 | 
			
		||||
                            while ($fn =~ s[/[^/]*\Z][]) {
 | 
			
		||||
                                $count_cats_sth->execute($fn) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                                if ($count_cats_sth->fetchrow_array) { # It exists
 | 
			
		||||
                                    last;
 | 
			
		||||
                                }
 | 
			
		||||
                                else {
 | 
			
		||||
                                    splice @missing_cats, $ins_pos, 0, $fn;
 | 
			
		||||
                                    mild_warning "$fn is needed for category $full_name and does not exist. It will be created";
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        warning "No father row found for $full_name! This may be a serious error as $full_name should probably have a father category";
 | 
			
		||||
                    }
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if ($$opt{data_integrity}) {
 | 
			
		||||
                $odbc and $count_cats_sth->finish;
 | 
			
		||||
                $count_cats_sth->execute($full_name) or critical "Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Category WHERE Full_Name = ?': ".$count_cats_sth->errstr;
 | 
			
		||||
                unless ($count_cats_sth->fetchrow_array) {
 | 
			
		||||
                    unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                        $Category_counter-- unless $$opt{straight_import};
 | 
			
		||||
                        warning "Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr;
 | 
			
		||||
                        next;
 | 
			
		||||
                    }
 | 
			
		||||
                    elsif (not $$opt{straight_import}) {
 | 
			
		||||
                        $cat_map[$old_id] = $new_id;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    mild_warning("Duplicate category found ($full_name) and skipped");
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                unless ($cat_ins_sth->execute($new_id,$name,$father_id,$full_name,@$row)) {
 | 
			
		||||
                    --$Category_counter unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert category `$full_name' (SQL query: `INSERT INTO ${e_prefix}Category $cat_ins_cols VALUES $cat_ins_vals'): ".$cat_ins_sth->errstr);
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                elsif (not $$opt{straight_import}) {
 | 
			
		||||
                    $cat_map[$old_id] = $new_id;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            import_print "$cats_imported Categories imported\n" unless ++$cats_imported % 500;
 | 
			
		||||
 | 
			
		||||
            my $num_of_links = 0;
 | 
			
		||||
            my $link_sub;
 | 
			
		||||
            $get_links_sth->execute($old_id) or critical "Unable to execute query: ".$get_links_sth->errstr;
 | 
			
		||||
            if ($odbc) {
 | 
			
		||||
                my $links_results = $get_links_sth->fetchall_arrayref;
 | 
			
		||||
                $get_links_sth->finish;
 | 
			
		||||
                $link_sub = sub { return shift @$links_results; }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $link_sub = sub { $get_links_sth->fetchrow_arrayref; }
 | 
			
		||||
            }
 | 
			
		||||
            while(my $row = $link_sub->()) {
 | 
			
		||||
                $row = [@$row];
 | 
			
		||||
                my ($id, $contact_name, $contact_email, $receive_mail, $cat_id) = splice @$row,0,5;
 | 
			
		||||
 | 
			
		||||
                unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
 | 
			
		||||
                $get_cat_alts->execute($id) or critical "Unable to execute query `SELECT CategoryID FROM $Links::DBSQL::CategoryAlternates::db_table WHERE LinkID = ?': ".$get_cat_alts->errstr;
 | 
			
		||||
                my @alt_ids;
 | 
			
		||||
                while (my $row = $get_cat_alts->fetchrow_arrayref) {
 | 
			
		||||
                    push @alt_ids, ($$opt{straight_import} ? $$row[0] : $cat_map[$$row[0]]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $id = ++$Links_counter unless $$opt{straight_import};
 | 
			
		||||
                my $username;
 | 
			
		||||
                $odbc and $user_count_sth->finish;
 | 
			
		||||
                $user_count_sth->execute($contact_email) or warning("Unable to execute query `SELECT COUNT(*) FROM ${e_prefix}Users WHERE Email = ?': ".$user_count_sth->errstr);
 | 
			
		||||
                if ($user_count_sth->fetchrow_array) { # This e-mail address already exists
 | 
			
		||||
                    $user_mod_sth->execute($contact_name, ($receive_mail eq 'Yes' ? 'Yes' : 'No'), $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                    $odbc and $username_sth->finish;
 | 
			
		||||
                    $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                    $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
                }
 | 
			
		||||
                elsif ($contact_email) {
 | 
			
		||||
                    $user_ins_sth->execute(($contact_email) x 2, '', (defined $contact_name ? $contact_name : ""), ($receive_mail eq 'Yes' ? 'Yes' : 'No')) or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Password, Email, Name, ReceiveMail, Status) VALUES (?, ?, ?, ?, 'Registered')': ".$user_ins_sth->errstr);
 | 
			
		||||
                    $username = $contact_email;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                    $username = 'admin';
 | 
			
		||||
                }
 | 
			
		||||
                if ($insert_link_sth->execute($id,$username,'Yes',@$row)) {
 | 
			
		||||
                    for ($new_id,@alt_ids) {
 | 
			
		||||
                        if (! defined $_) { next; }
 | 
			
		||||
                        $cat_links_sth->execute($id,$_) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                    }
 | 
			
		||||
                    $num_of_links++;
 | 
			
		||||
                    import_print "$links_imported Links imported\n" unless ++$links_imported % 500;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    $Links_counter-- unless $$opt{straight_import};
 | 
			
		||||
                    warning("Unable to insert validated link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $links_ins_cols VALUES $links_ins_vals'): ".$insert_link_sth->errstr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
                # Even with a straight import, Validate ID's cannot stay the same because they would conflict with link ID's.
 | 
			
		||||
                my $sth = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Links") or critical "Unable to prepare query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$e_dbh->errstr;
 | 
			
		||||
                $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM ${e_prefix}Links': ".$sth->errstr;
 | 
			
		||||
                $Links_counter = $sth->fetchrow_array;
 | 
			
		||||
                $sth->finish;
 | 
			
		||||
                if ($$opt{straight_import}) {
 | 
			
		||||
                    # For a straight import, we need to make sure that the link ID's used
 | 
			
		||||
                    # for non-validated links start after the highest old Link ID.
 | 
			
		||||
                    $sth = $i_dbh{$Links::DBSQL::Links::db_name}->prepare("SELECT MAX(ID) FROM $Links::DBSQL::Users::db_table") or critical "Unable to prepare query `SELECT MAX(ID) FROM $Links::DBSQL::Users::db_table: ".$i_dbh{$Links::DBSQL::Links::db_name}->errstr;
 | 
			
		||||
                    $sth->execute or critical "Unable to execute query `SELECT MAX(ID) FROM $Links::DBSQL::Users::db_table: ".$sth->errstr;
 | 
			
		||||
                    my $old_max = $sth->fetchrow_array;
 | 
			
		||||
                    $sth->finish;
 | 
			
		||||
                    $Links_counter = $old_max if $old_max > $Links_counter;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $get_vlinks_sth->execute($old_id) or critical "Unable to execute query: ".$get_vlinks_sth->errstr;
 | 
			
		||||
            if ($odbc) {
 | 
			
		||||
                my $links_results = $get_vlinks_sth->fetchall_arrayref;
 | 
			
		||||
                $get_vlinks_sth->finish;
 | 
			
		||||
                $link_sub = sub { return shift @$links_results }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $link_sub = sub { $get_vlinks_sth->fetchrow_arrayref }
 | 
			
		||||
            }
 | 
			
		||||
            while(my $row = $link_sub->()) {
 | 
			
		||||
                $row = [@$row]; # Get rid of a peculiar read-only aliasing in DBI
 | 
			
		||||
                my ($id, $contact_name, $contact_email, $receive_mail, $cat_id) = splice @$row,0,5;
 | 
			
		||||
 | 
			
		||||
                unshift @$row, $contact_name, $contact_email;
 | 
			
		||||
 | 
			
		||||
                $get_cat_alts->execute($id) or critical "Unable to execute query `SELECT CategoryID FROM $Links::DBSQL::CategoryAlternates::db_table WHERE LinkID = ?': ".$get_cat_alts->errstr;
 | 
			
		||||
                my @alt_ids;
 | 
			
		||||
                while (my $row = $get_cat_alts->fetchrow_arrayref) {
 | 
			
		||||
                    push @alt_ids, ($$opt{straight_import} ? $$row[0] : $cat_map[$$row[0]]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $id = ++$Links_counter;
 | 
			
		||||
                my $username;
 | 
			
		||||
                $user_count_sth->execute($contact_email) or warning("Unable to execute query: ".$user_count_sth->errstr);
 | 
			
		||||
                if ($user_count_sth->fetchrow_array) { # Exists
 | 
			
		||||
                    $user_mod_sth->execute($contact_name, ($receive_mail eq 'Yes' ? 'Yes' : 'No'), $contact_email) or warning("Unable to execute query `UPDATE ${e_prefix}Users SET Name = ?, ReceiveMail = ? WHERE Email = ?': ".$user_mod_sth->errstr);
 | 
			
		||||
                    $username_sth->execute($contact_email) or warning("Unable to execute query: ".$username_sth->errstr);
 | 
			
		||||
                    $username = $username_sth->fetchrow_arrayref()->[0];
 | 
			
		||||
                }
 | 
			
		||||
                elsif ($contact_email) { # Doesn't exist, but we can make the e-mail address into a username
 | 
			
		||||
                    $user_ins_sth->execute(($contact_email) x 2, '', (defined $contact_name ? $contact_name : ""), ($receive_mail eq 'Yes' ? 'Yes' : 'No')) or warning("Unable to execute query `INSERT INTO ${e_prefix}Users (Username, Email, Name, ReceiveMail) VALUES (?, ?, ?, ?, ?)': ".$user_ins_sth->errstr);
 | 
			
		||||
                    $username = $contact_email;
 | 
			
		||||
                }
 | 
			
		||||
                else { # Can't make a user; use the `admin' user.
 | 
			
		||||
                    mild_warning("Not enough information to add a user for link `".($$row[0] or '<unknown>')." (URL: ".($$row[1] or "<none>")."). Setting link owner to `admin'");
 | 
			
		||||
                    $username = 'admin';
 | 
			
		||||
                }
 | 
			
		||||
                if ($insert_vlink_sth->execute($id,$username,'No',@$row)) {
 | 
			
		||||
                    for ($id,@alt_ids) {
 | 
			
		||||
                        $cat_links_sth->execute($_,$new_id) or warning "Unable to execute query `INSERT INTO ${e_prefix}CatLinks (LinkID, CategoryID) VALUES (?, ?)': ".$cat_links_sth->errstr;
 | 
			
		||||
                    }
 | 
			
		||||
                    $num_of_links++;
 | 
			
		||||
                    import_print "$links_imported Links imported\n" unless ++$links_imported % 500;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    $Links_counter--;
 | 
			
		||||
                    warning("Unable to insert non-validated link `$$row[0]' (SQL query: `INSERT INTO ${e_prefix}Links $validate_ins_cols VALUES $validate_ins_vals'): ".$insert_vlink_sth->errstr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $num_links_sth->execute($num_of_links,$new_id) or warning "Unable to execute query `UPDATE ${e_prefix}Category SET Number_of_Links = ? WHERE ID = ?': ".$num_links_sth->errstr;
 | 
			
		||||
        }
 | 
			
		||||
        my $missing_cats;
 | 
			
		||||
        if ($$opt{create_missing_categories} and @missing_cats) {
 | 
			
		||||
            my $counter = $e_dbh->prepare("SELECT MAX(ID) FROM ${e_prefix}Category");
 | 
			
		||||
            $counter->execute();
 | 
			
		||||
            my $count = $counter->fetchrow_array();
 | 
			
		||||
            my $update_sub_cats = $e_dbh->prepare("UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?") or critical "Unable to prepare query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? AND Full_Name NOT LIKE ?': ".$e_dbh->errstr;
 | 
			
		||||
            for (@missing_cats) {
 | 
			
		||||
                my ($name) = m[([^/]+)\Z];
 | 
			
		||||
                my ($father_full) = m[\A(.*)/];
 | 
			
		||||
                my $father_id;
 | 
			
		||||
                if ($father_full) {
 | 
			
		||||
                    $father_sth->execute($father_full) or critical "Unable to execute query `SELECT ID FROM ${e_prefix}Category WHERE Full_Name = ?': ".$father_sth->errstr;
 | 
			
		||||
                    $father_id = $father_sth->fetchrow_array;
 | 
			
		||||
                }
 | 
			
		||||
                else { # Must be a root category
 | 
			
		||||
                    $father_id = 0;
 | 
			
		||||
                }
 | 
			
		||||
                $cat_ins_simple_sth->execute(++$count,$name,$_,$father_id) or critical "Unable to create missing category $_: ".$cat_ins_simple_sth->errstr;
 | 
			
		||||
                $update_sub_cats->execute($count,"$_/%","$_/%/%") or critical "Unable to execute query `UPDATE ${e_prefix}Category SET FatherID = ? WHERE Full_Name LIKE ? and Full_Name NOT LIKE ?': ".$update_sub_cats->errstr;
 | 
			
		||||
                $missing_cats++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        import_print "$cats_imported Categories imported";
 | 
			
		||||
        import_print ", $missing_cats missing categories created" if $missing_cats;
 | 
			
		||||
        import_print ".\n";
 | 
			
		||||
        import_print "$links_imported Links imported.\n";
 | 
			
		||||
 | 
			
		||||
# Category Relations:
 | 
			
		||||
        if ($$opt{straight_import}) {
 | 
			
		||||
            $get_cat_relations->execute or critical "Unable to execute query `SELECT CategoryID, RelatedID from $Links::DBSQL::CategoryRelations::db_table': ".$get_cat_relations->errstr;
 | 
			
		||||
            while (my $row = $get_cat_relations->fetchrow_arrayref) {
 | 
			
		||||
                $add_cat_relation->execute(@$row) or warning "Unable to add category relation for categories with ID's $$row[0] and $$row[1]. Reason: ".$add_cat_relation->errstr;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $get_cat_relations->execute or critical "Unable to execute query `SELECT CategoryID, RelatedID from $Links::DBSQL::CategoryRelations::db_table': ".$get_cat_relations->errstr;
 | 
			
		||||
            while (my $row = $get_cat_relations->fetchrow_arrayref) {
 | 
			
		||||
                $add_cat_relation->execute(@cat_map[@$row]) or warning "Unable to add category relation for categories with ID's: (new: $cat_map[$$row[0]], old: $$row[0]) and (new: $cat_map[$$row[1]], old: $$row[1]). Reason: ".$add_cat_relation->errstr;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (keys %i_dbh) {
 | 
			
		||||
        $i_dbh{$_}->disconnect;
 | 
			
		||||
    }
 | 
			
		||||
    $e_dbh->disconnect;
 | 
			
		||||
    import_print "\nNOTE: You must run Rebuild Cat. tree, Repair Tables, and Rebuild Search after performing an import!\n";
 | 
			
		||||
 | 
			
		||||
    1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Returns a random password of random length (20-25 characters).
 | 
			
		||||
sub random_pass () {
 | 
			
		||||
    my @chars = ('a'..'z','A'..'Z',0..9,qw a _ [ ] { } ` ' " ! @ ^ * ( ) - _ = + : ; . / \ a,'#',',');
 | 
			
		||||
    my $pass = join '', map { $chars[rand @chars] } 0..(20+rand(5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
							
								
								
									
										152
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/S2BK.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								site/slowtwitch.com/cgi-bin/articles/admin/Links/Import/S2BK.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
# ==================================================================
 | 
			
		||||
# Gossamer Links - enhanced directory management system
 | 
			
		||||
#
 | 
			
		||||
#   Website  : http://gossamer-threads.com/
 | 
			
		||||
#   Support  : http://gossamer-threads.com/scripts/support/
 | 
			
		||||
#   CVS Info : 087,071,086,086,085      
 | 
			
		||||
#   Revision : $Id: S2BK.pm,v 1.13 2009/05/09 06:35:25 brewt 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::Import::S2BK;
 | 
			
		||||
 | 
			
		||||
use 5.004_04;
 | 
			
		||||
use strict;
 | 
			
		||||
use vars qw/$Warning_Code $Critical_Code $Mild_Code $Print_Out/;
 | 
			
		||||
 | 
			
		||||
use GT::SQL;
 | 
			
		||||
use Links qw/$CFG/;
 | 
			
		||||
 | 
			
		||||
sub critical {
 | 
			
		||||
    $Critical_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub warning {
 | 
			
		||||
    $Warning_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mild_warning {
 | 
			
		||||
    ref $Mild_Code eq 'CODE' and $Mild_Code->(@_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub import_print {
 | 
			
		||||
    if (ref $Print_Out eq 'CODE') {
 | 
			
		||||
        $Print_Out->(@_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        print @_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes 3-4 arguments: hash reference, 2 or 3 code refs
 | 
			
		||||
# The hash reference is the options hash for an import.
 | 
			
		||||
# The first code reference will be called when a warning occurs.
 | 
			
		||||
# The second code reference will be called when a critical error occurs.
 | 
			
		||||
# If provided, the third code reference will be called when a mild warning occurs
 | 
			
		||||
sub import {
 | 
			
		||||
    my $opt = shift;
 | 
			
		||||
    return if ref $opt ne 'HASH';
 | 
			
		||||
    {
 | 
			
		||||
        my $warning = shift;
 | 
			
		||||
        return if ref $warning ne 'CODE';
 | 
			
		||||
        $Warning_Code = $warning;
 | 
			
		||||
 | 
			
		||||
        my $critical = shift;
 | 
			
		||||
        return if ref $critical ne 'CODE';
 | 
			
		||||
        $Critical_Code = $critical;
 | 
			
		||||
 | 
			
		||||
        my $mild = shift;
 | 
			
		||||
        $Mild_Code = $mild if ref $mild eq 'CODE';
 | 
			
		||||
 | 
			
		||||
        my $output = shift;
 | 
			
		||||
        $Print_Out = $output if ref $output eq 'CODE';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $DB = new GT::SQL(def_path => $$opt{source}, subclass => 0);
 | 
			
		||||
    my $prefix = $DB->prefix || "";
 | 
			
		||||
 | 
			
		||||
    my $delimiter = $$opt{delimiter};
 | 
			
		||||
    critical "Invalid delimiter `".(defined$delimiter?$delimiter:'')."' for a delimited file!"
 | 
			
		||||
        unless defined $delimiter and length $delimiter == 1 and $delimiter ne '\\';
 | 
			
		||||
 | 
			
		||||
    my @tables;
 | 
			
		||||
    opendir (D, "$CFG->{admin_root_path}/defs") or critical "unable to opendir $CFG->{admin_root_path}/defs ($!)";
 | 
			
		||||
    while (defined (my $def = readdir(D))) {
 | 
			
		||||
        next unless $def =~ /^\Q$prefix\E(.*)\.def$/;
 | 
			
		||||
        push @tables, $1 if $1 !~ /_(?:Word|Score)_List$/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    local ($,,$\,*EXPORT_FH);
 | 
			
		||||
    open EXPORT_FH, "> $$opt{destination}" or critical "Unable to open $$opt{destination} for writing: $!";
 | 
			
		||||
    binmode EXPORT_FH; # this is NOT a text file.
 | 
			
		||||
    print EXPORT_FH "Links SQL 2 backup. This backup was generated at "   .   gmtime()   .   " UTC. THIS FILE IS NOT A TEXT FILE. You should NOT attempt to edit this file as you will end up corrupting the data contained in it.\0";
 | 
			
		||||
 | 
			
		||||
=pod
 | 
			
		||||
Schematic for the file:
 | 
			
		||||
 | 
			
		||||
- Newline delimiter is changed to \0 (hex and ascii 0).
 | 
			
		||||
- Each line starting with '\\\\' starts off a new table.
 | 
			
		||||
- The first line following the '\\\\' is the table name by itself (NOT prefixed).
 | 
			
		||||
- The first character of the line after that is the delimiter for that table, and
 | 
			
		||||
  the rest of that line is the columns of the table delimited by the delimiter.
 | 
			
		||||
- All subsequent lines (until another '\\\\') are individual records.
 | 
			
		||||
- All fields (headers and records) are escaped where needed in '\\XX' format
 | 
			
		||||
  (where 'XX' is the hexadecimal representation of the character).
 | 
			
		||||
- All lines until the first '\\\\' are treated as comments and are ignored.
 | 
			
		||||
- Everything following '\\\\' is treated as a comment and is ignored.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
    for my $t (@tables) {
 | 
			
		||||
        $GT::SQL::error = '';
 | 
			
		||||
        my $table = $DB->table($t);
 | 
			
		||||
        my $count = $table->count;
 | 
			
		||||
        next if $GT::SQL::error;
 | 
			
		||||
 | 
			
		||||
        import_print "Exporting $prefix$t ...\n";
 | 
			
		||||
        print EXPORT_FH "\\\\ The following is table $t".($prefix ? " (from prefixed table $prefix$t)" : "")."\0";
 | 
			
		||||
        print EXPORT_FH "$t\0";
 | 
			
		||||
        print EXPORT_FH $delimiter; # The first character on this line is the delimiter
 | 
			
		||||
        local ($a,$b);
 | 
			
		||||
        print EXPORT_FH join($delimiter, sort { $table->{schema}{cols}{$a}{pos} <=> $table->{schema}{cols}{$b}{pos} } map BK_escape($_,$delimiter), keys %{$table->cols}),"\0";
 | 
			
		||||
        my $sth;
 | 
			
		||||
        my $printed = 0;
 | 
			
		||||
        for my $i (0 .. $count/1000) {
 | 
			
		||||
            $sth = $table->prepare("SELECT * FROM $prefix$t LIMIT ".($i * 1000).", 1000") or critical "Unable to prepare query `SELECT * FROM $prefix$t LIMIT ".($i * 1000).", 1000': ".$sth->errstr;
 | 
			
		||||
            $sth->execute();
 | 
			
		||||
            while (my $row = $sth->fetchrow_arrayref) {
 | 
			
		||||
                print EXPORT_FH join($delimiter, map BK_escape($_,$delimiter), @$row),"\0";
 | 
			
		||||
                unless (++$printed % 500) {
 | 
			
		||||
                    import_print "$printed records from $prefix$t exported ...\n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        import_print "$printed records from $prefix$t exported.\n",
 | 
			
		||||
                     "All records from $prefix$t have been exported.\n\n";
 | 
			
		||||
    }
 | 
			
		||||
    close EXPORT_FH;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Takes two parameters: The field to escape, and the delimiter. It will return
 | 
			
		||||
# the escaped form of the field.
 | 
			
		||||
sub BK_escape ($$) {
 | 
			
		||||
    return unless defined wantarray;
 | 
			
		||||
    my $field = shift;
 | 
			
		||||
    my $delimiter = shift;
 | 
			
		||||
    $delimiter = "" unless defined $delimiter;
 | 
			
		||||
    critical "Bad delimiter `$delimiter'" unless length $delimiter == 1 and $delimiter ne '\\';
 | 
			
		||||
    my $escape_chr = '\\';
 | 
			
		||||
    if (not defined $field) {
 | 
			
		||||
        return 'NULL';
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($field eq 'NULL') {
 | 
			
		||||
        return 'NUL\4C'; # If it is the actual string 'NULL' this will keep it
 | 
			
		||||
    } # from being recognized as a NULL field when it is read in again.
 | 
			
		||||
    $field =~ s/([\Q$delimiter$escape_chr\E\x00-\x1f])/sprintf '\%02X', ord $1/ge;
 | 
			
		||||
    $field;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"Once upon a time, in a galaxy far, far away . . . There was a true value";
 | 
			
		||||
		Reference in New Issue
	
	Block a user