# ==================================================================
# Gossamer List - enhanced mailing list management system
#
#   Website  : http://gossamer-threads.com/
#   Support  : http://gossamer-threads.com/scripts/support/
#   CVS Info :                          
#   Revision : $Id: SQL.pm,v 1.40 2004/10/05 22:02:27 bao Exp $
#
# Copyright (c) 2004 Gossamer Threads Inc.  All Rights Reserved.
# Redistribution in part or in whole strictly prohibited.  Please
# see LICENSE file for full details.
# ==================================================================
#

package GList::SQL;

use strict;
use vars  qw/@TABLES $EMAIL_RE/;
use GList qw/$DB $CFG/;

@TABLES = qw/Users Users_Sessions EmailTemplates Messages Lists Subscribers
MailingIndex EmailMailings CatMessages CatMailing MessageAttachments
MailingAttachments StopLists/;

$EMAIL_RE = '.@\S+\.\S+$';

# Index naming format:
#
# a_bcd[_q]
#
# Where "a" is (usually) the capital letters from the table name (i.e. EmailTemplates gets "et"),
# except for CatMailing, which is cml, and MailingAttachments, which is mla.
#
# b,c,d,... correspond to the following:
#
# b - sub_bounced
# c - *_cat_id_fk | eml_code
# d - session_date | mli_delete
# e - usr_email | sub_email | stl_email
# l - *_list_id_fk
# m - *_message_id_fk
# n - tpl_name | mli_done
# t - lst_title
# u - *_user_id_fk
# v - sub_validated
#
# Finally, the optional "_q" is used for unique indices.
# 

sub tables {
#----------------------------------------------------------------
# Defines the SQL tables
#
    my $action = shift || 'warn';
    my $output = '';

#---------- Users Table -----------------
    create_table(\$output, 'Users', $action,
        cols => [
            usr_username        => { type => 'CHAR', size => 50, not_null => 1, form_display => 'User Name' },
            usr_email           => { type => 'CHAR', size => 50, not_null => 1, form_display => 'Email Address', form_regex => $EMAIL_RE },
            usr_password        => { type => 'CHAR', size => 100, not_null => 1, form_display => 'Password' },
            usr_type            => { type => 'TINYINT', not_null => 1, default => 1, form_display => 'Type' },
            usr_reply_email     => { type => 'CHAR', size => 100, not_null => 0, form_display => 'Reply to Email', form_regex => $EMAIL_RE },
            usr_bounce_email    => { type => 'CHAR', size => 100, not_null => 0, form_display => 'Bounce Email', form_regex => $EMAIL_RE },
            usr_date_format     => { type => 'CHAR', size => 50, form_display => 'Date Format' },
            usr_compose_mode    => { type => 'CHAR', size => 5, form_display  => 'Editor Advanced', default => 'text' },
            usr_editor_advanced => { type => 'TINYINT', not_null => 1, default => 0 },
            usr_status          => { type => 'TINYINT', default  => '1', form_display => 'Status' },
            usr_limit_list      => { type => 'INT', default  => '0', form_display => 'Limit Number of List' },
            usr_limit_sublist   => { type => 'INT', default  => '0', form_display => 'Limit Number of subscriber per List' },
            usr_limit_email30   => { type => 'INT', default  => '0', form_display => 'Limit Number of Email Sending in The Last 30 days' },
            usr_mail_host       => { type => 'CHAR', size => 100, form_display => 'Server Mail hostname' },
            usr_mail_port       => { type => 'CHAR', size => 3, form_display => 'Server Mail port' },
            usr_mail_account    => { type => 'CHAR', size => 50, form_display => 'Mail Account' },
            usr_mail_password   => { type => 'CHAR', size => 20, form_display => 'Mail Password' },
            usr_validate_code   => { type => 'CHAR', size => 32, binary => 1, form_display => 'Validate Code' },
            usr_updated         => { type => 'TINYINT', default  => '0', form_display => 'Account Updated' },
            usr_header_html     => { type => 'TEXT', default  => '', form_display => 'Mailing Header' },
            usr_header_text     => { type => 'TEXT', default  => '', form_display => 'Mailing Header' },
            usr_footer_html     => { type => 'TEXT', default  => '', form_display => 'Mailing Footer' },
            usr_footer_text     => { type => 'TEXT', default  => '', form_display => 'Mailing Footer' },
            pro_first_name      => { type => 'CHAR', size => 20, not_null => 1, form_display => 'First Name', form_size => '35' },
            pro_last_name       => { type => 'CHAR', size => 30, not_null => 1, form_display => 'Last Name', form_size => '35'  },
            pro_company         => { type => 'CHAR', size => 100, form_display => 'Company Name', form_size => '35' },
            pro_url             => { type => 'CHAR', size => 255, form_display => 'URL', form_size => '35' },
        ],
        pk => 'usr_username',
        unique => {
            u_e_q => ['usr_email']
        }
    );

#---------- Users_Sessions Table -----------------
    create_table(\$output, 'Users_Sessions', $action,
        cols => [
            session_id      => { type => 'CHAR', binary => 1, size => 32, not_null => 1 },
            session_user_id => { type => 'CHAR', size => 50 },
            session_date    => { type => 'INT', not_null => 1 },
            session_data    => { type => 'TEXT' }
        ],
        pk => 'session_id',
        fk => {
            Users => { session_user_id => 'usr_username' }
        },
        index => {
            us_d => ['session_date']
        }
    );

#---------- EmailTemplates Table -----------------
    create_table(\$output, 'EmailTemplates', $action,
        cols => [
            tpl_id          => { type => 'INT',  not_null=> 1, form_display => 'ID' },
            tpl_user_id_fk  => { type => 'CHAR', size    => 50, not_null => 1, form_display => 'User Name' },
            tpl_name        => { type => 'CHAR', size    => 50, not_null => 1, form_display => 'Template Name' },
            tpl_to          => { type => 'CHAR', size    => 50, not_null => 1, form_display => 'To' },
            tpl_subject     => { type => 'CHAR', size    => 100,not_null => 1, form_display => 'Subject' },
            tpl_from        => { type => 'CHAR', size    => 100,not_null => 1, form_display => 'From' },
            tpl_extra       => { type => 'CHAR', size    => 255, form_display => 'Extra Header' },
            tpl_body        => { type => 'TEXT', not_null=> 1, form_display => 'Email Body' },
        ],
        pk => 'tpl_id',
        ai => 'tpl_id',

        unique => {
            et_un_q => [qw/tpl_user_id_fk tpl_name/]
        },
        fk => { Users => { tpl_user_id_fk => 'usr_username' } }
    );

#---------- CatMessages Table -----------------
    create_table(\$output, 'CatMessages', $action,
        cols => [
            cms_id          => { type => 'INT',  not_null => 1, form_display => 'ID' },
            cms_name        => { type => 'CHAR', not_null => 1, size => 30, form_display => 'Folder Name' },
            cms_user_id_fk  => { type => 'CHAR', not_null => 1, size => 50, form_display => 'User ID' },
        ],
        pk => 'cms_id',
        ai => 'cms_id',
        index => {
            cm_u => ['cms_user_id_fk']
        },
        fk => { Users => { cms_user_id_fk => 'usr_username' } }
    );

#---------- Messages Table -----------------
    create_table(\$output, 'Messages', $action,
        cols => [
            msg_id           => { type => 'INT', not_null => 1, form_display => 'Message ID' },
            msg_mode         => { type => 'CHAR', size   => 5, default => 'text', form_display => 'Message Mode' },
            msg_charset      => { type => 'CHAR', size   => 15, not_null => 1, default => 'us-ascii', form_display => 'Charset'},
            msg_subject      => { type => 'CHAR', size   => 100, not_null => 1, form_display => 'Subject', 'weight' => '1' },
            msg_from_name    => { type => 'CHAR', size   => 70, form_display => 'From Name' },
            msg_from_email   => { type => 'CHAR', size   => 100, not_null => 1, form_display => 'From Email', form_regex => $EMAIL_RE },
            msg_reply_to     => { type => 'CHAR', size   => 100, not_null => 1, form_display => 'Reply to Email', form_regex => $EMAIL_RE },
            msg_bounce_email => { type => 'CHAR', size   => 100, not_null => 1, form_display => 'Bounce Email', form_regex => $EMAIL_RE },
            msg_created      => { type => 'INT', form_display => 'Name' },
            msg_content_text => { type => 'LONGTEXT', form_display => 'TEXT Content', 'weight' => '1' },
            msg_content_html => { type => 'LONGTEXT', form_display => 'HTML Content', 'weight' => '1' },
            msg_cat_id_fk    => { type => 'INT',  default => 0, not_null => 1, form_display => 'Category ID' },
            msg_status       => { type => 'TINYINT', default => 0, form_display => 'Status' },
            msg_track_open   => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Track Number of Users opening this message' },
            msg_track_click  => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Track Number of Clicks' },
            msg_user_id_fk   => { type => 'CHAR', size   => 50, not_null => 1, form_display => 'User ID' },
        ],
        pk => 'msg_id',
        ai => 'msg_id',
        fk => {
            Users => { msg_user_id_fk => 'usr_username' },
            CatMessages => { msg_cat_id_fk => 'cms_id' }
        },
        index => {
            m_uc => [qw/msg_user_id_fk msg_cat_id_fk/]
        }
    );

#---------- MessageAttachments Table -----------------
    create_table(\$output, 'MessageAttachments', $action,
        cols => [
            att_id              => { type => 'INT',  not_null => 1, form_display => 'ID' },
            att_message_id_fk   => { type => 'INT',  not_null => 1, form_display => 'Campaign ID' },
            att_file_name       => { type => 'CHAR', size => 255, form_display => 'File Name' },
            att_file_size       => { type => 'INT',  form_display => 'File Size' },
        ],
        pk => 'att_id',
        ai => 'att_id',
        fk => { Messages => { att_message_id_fk => 'msg_id' } },
        index => {
            ma_m => ['att_message_id_fk']
        }
    );

#---------- Lists Table -----------------
    create_table(\$output, 'Lists', $action,
        cols => [
            lst_id                      => { type => 'INT', not_null  => 1, form_display => 'List ID' },
            lst_title                   => { type => 'CHAR', size => 50, not_null => 1,  form_display => 'List Name', weight => '1' },
            lst_description             => { type => 'TEXT',             form_display => 'Name', weight => '1' },
            lst_opt                     => { type => 'TINYINT', form_display => 'Double Opt In', default => '0' },
            lst_opt_template            => { type => 'CHAR', size => 50, form_display => 'Opt In Template' },
            lst_subs_template           => { type => 'CHAR', size => 50, form_display => 'Subscriber Template' },
            lst_unsubs_template         => { type => 'CHAR', size => 50, form_display => 'Unsubscriber Template' },
            lst_date_created            => { type => 'INT', form_display => 'Created' },
            lst_url_subscribe_success   => { type => 'CHAR', size => 255, form_display => 'Success Subscribe URL' },
            lst_url_validate_success    => { type => 'CHAR', size => 255, form_display => 'Success Validate URL' },
            lst_url_unsubscribe_success => { type => 'CHAR', size => 255, form_display => 'Success Unsubscribe URL' },
            lst_url_subscribe_failure   => { type => 'CHAR', size => 255, form_display => 'Failure Subscribe URL' },
            lst_url_unsubscribe_failure => { type => 'CHAR', size => 255, form_display => 'Failure Unsubscribe URL' },
            lst_user_id_fk              => { type => 'CHAR', size => 50, not_null => 1, form_display => 'User ID' },
        ],
        pk => 'lst_id',
        ai => 'lst_id',
        fk => { Users => { lst_user_id_fk => 'usr_username' } },
        index => {
            l_ut => [qw/lst_user_id_fk lst_title/]
        }
    );

#---------- Subscribers Table -----------------
    create_table(\$output, 'Subscribers', $action,
        cols => [
            sub_id          => { type => 'INT', not_null => 1, form_display => 'Subscriber ID' },
            sub_email       => { type => 'CHAR', size => 50, not_null => 1, form_display => 'Subscriber Email', form_regex => $EMAIL_RE, weight => '1' },
            sub_name        => { type => 'CHAR', size => 50, form_display => 'Subscriber Name', weight => '1' },
            sub_created     => { type => 'INT', form_display => 'Created' },
            sub_list_id_fk  => { type => 'INT', not_null => 1, form_display => 'List ID' },
            sub_validated   => { type => 'TINYINT', not_null => 1, default => 1, form_display => 'Validated' },
            sub_val_code    => { type => 'CHAR', size => 50, form_display => 'Validation Code' },
            sub_bounced     => { type => 'INT', not_null => 1, default => 0, form_display => 'Bounced Email' },
            sub_user_id_fk  => { type => 'CHAR', size => 50, not_null => 1, form_display => 'User ID' },
        ],

        pk => 'sub_id',
        ai => 'sub_id',
        fk => {
            Lists => { sub_list_id_fk => 'lst_id' },
            Users => { sub_user_id_fk => 'usr_username' }
        },
        index => {
            s_lb  => [qw/sub_list_id_fk sub_bounced/],
            s_lvb => [qw/sub_list_id_fk sub_validated sub_bounced/],
            s_ue  => [qw/sub_user_id_fk sub_email/],
            s_e   => [qw/sub_email/]
        },
        unique => {
            s_le_q  => [qw/sub_list_id_fk sub_email/]
        }
    );

#---------- CatMailing Table -----------------
    create_table(\$output, 'CatMailing', $action,
        cols => [
            cm_id           => { type => 'INT',  not_null => 1, form_display => 'ID' },
            cm_name         => { type => 'CHAR', not_null => 1, size => 30, form_display => 'Folder Name' },
            cm_type         => { type => 'TINYINT', default => '1', form_display => 'Type' },
            cm_user_id_fk   => { type => 'CHAR', not_null => 1, size => 50, form_display => 'User ID' },
        ],
        pk => 'cm_id',
        ai => 'cm_id',
        fk => { Users => { cm_user_id_fk => 'usr_username' } },
        index => {
            cml_u => ['cm_user_id_fk']
        }
    );

#---------- MailingIndex Table -----------------
    create_table(\$output, 'MailingIndex', $action,
        cols => [
            mli_id           => { type => 'INT',  not_null => 1, form_display => 'Mailing ID' },
            mli_done         => { type => 'INT',  default  => 0, form_display => 'Done' },
            mli_from         => { type => 'CHAR', size     => 100, form_display => 'From Email', form_regex => $EMAIL_RE },
            mli_name         => { type => 'CHAR', size     => 50, form_display => 'From Name' },
            mli_reply_to     => { type => 'CHAR', size     => 100, form_display => 'Reply To Email', form_regex => $EMAIL_RE },
            mli_bounce_email => { type => 'CHAR', size     => 100, form_display => 'Bounce Email', form_regex => $EMAIL_RE },
            mli_charset      => { type => 'CHAR', size     => 15, not_null => 1, default => 'us-ascii', form_display => 'Charset'},
            mli_subject      => { type => 'CHAR', size     => 100, form_display => 'Subject', 'weight' => '1' },
            mli_message_text => { type => 'LONGTEXT', form_display => 'TEXT Message', 'weight' => '1' },
            mli_message_html => { type => 'LONGTEXT', form_display => 'HTML Message', 'weight' => '1' },
            mli_cat_id_fk    => { type => 'INT',     not_null => 1, default => 0, form_display => 'Category ID' },
            mli_delete       => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Delete' },
            mli_track_open   => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Track Number of Users opening this message' },
            mli_track_click  => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Track Number of clicks' },
            mli_num_opened   => { type => 'INT', not_null => 1, default => 0, form_display => 'Number of Users opening this message' },
            mli_num_clicked  => { type => 'INT', not_null => 1, default => 0, form_display => 'Number of clicks' },
            mli_scheduled    => { type => 'TINYINT', not_null => 1, default => 0, form_display => 'Scheduled Mailing' },
            mli_user_id_fk   => { type => 'CHAR', size     => 50, not_null => 1, form_display => 'User ID' }
        ],
        pk => 'mli_id',
        ai => 'mli_id',
        fk => {
            Users => { mli_user_id_fk => 'usr_username' },
            CatMailing => { mli_cat_id_fk => 'cm_id' }
        },

        index => {
            mi_ucdn => [qw/mli_user_id_fk mli_cat_id_fk mli_delete mli_done/],
            mi_c  => ['mli_cat_id_fk']
        }
    );

#---------- EmailMailings Table -----------------
    create_table(\$output, 'EmailMailings', $action,
        cols => [
            eml_id              => { type => 'INT',  not_null => 1,  form_display => 'ID' },
            eml_mailing_id_fk   => { type => 'INT',  not_null => 1,  form_display => 'Mailing ID' },
            eml_email           => { type => 'CHAR', size     => 50, not_null => 1, form_display => 'Email Address', form_regex => $EMAIL_RE },
            eml_name            => { type => 'CHAR', size     => 50, form_display => 'Name' },
            eml_sent            => { type => 'INT', not_null => 1, default => 0 },
            eml_bounced         => { type => 'TINYINT', not_null => 1, default => 0 },
            eml_skipped         => { type => 'TINYINT', not_null => 1, default => 0 },
            eml_opened          => { type => 'INT', not_null => 1, default => 0 },
            eml_code            => { type => 'CHAR', size => 100 => not_null => 1 },
            eml_lists           => { type => 'TEXT', default  => '' },
        ],
        pk => 'eml_id',
        ai => 'eml_id',
        fk => { MailingIndex => { eml_mailing_id_fk => 'mli_id' } },
        index => {
            em_mb => [qw/eml_mailing_id_fk eml_bounced/],
            em_ms => [qw/eml_mailing_id_fk eml_sent/],
            em_mo => [qw/eml_mailing_id_fk eml_opened/],
            em_e  => [qw/eml_email/],
            em_c  => [qw/eml_code/],
        },
        unique => {
            em_me_q => [qw/eml_mailing_id_fk eml_email/]
        }
    );

#---------- ScheduledMailings Table -----------------
    create_table(\$output, 'ScheduledMailings', $action,
        cols => [
            scm_id            => { type => 'INT', not_null => 1, form_display => 'Schedule ID'},
            scm_hour          => { type => 'INT', default => 0, form_display => 'Hour' },
            scm_minute        => { type => 'INT', default => 0, form_display => 'Minute' },
            scm_type          => { type => 'TINYINT', default => 0, form_display => 'Schedule Type' },
            scm_option        => { type => 'CHAR', size => 10, default => '', form_display => 'Option' },
            scm_text_url      => { type => 'CHAR', size => 225, default => '', form_display => 'Text URL' },
            scm_html_url      => { type => 'CHAR', size => 225, default => '', form_display => 'Html URL' },
            scm_inprocess     => { type => 'TINYINT', default => 0, form_display => 'In Process' },
            scm_sent          => { type => 'INT', default => 0, form_display => 'Sent Time' },
            scm_mailing_id_fk => { type => 'INT', default => 0, form_display => 'Mailing ID' },
        ],
        ai     => 'scm_id',
        pk     => 'scm_id',
        unique => {
            sm_m_q => [qw/scm_mailing_id_fk/]
        },
        fk     => { MailingIndex => { scm_mailing_id_fk => 'mli_id' } }
    );

#---------- MailingAttachments Table -----------------
    create_table(\$output, 'MailingAttachments', $action,
        cols => [
            mat_id              => { type => 'INT',  not_null => 1,   form_display => 'ID' },
            mat_mailing_id_fk   => { type => 'INT',  not_null => 1,   form_display => 'Mailing ID' },
            mat_file_name       => { type => 'CHAR', size     => 255, form_display => 'File Name' },
            mat_file_size       => { type => 'INT',                   form_display => 'File Size' },
        ],
        pk => 'mat_id',
        ai => 'mat_id',
        fk => { MailingIndex => { mat_mailing_id_fk => 'mli_id' } },
        index => {
            mla_m => ['mat_mailing_id_fk']
        }
    );

#---------- StopLists Table -----------------
    create_table(\$output, 'StopLists', $action,
        cols => [
            stl_id          => { type => 'INT',  not_null => 1,   form_display => 'ID' },
            stl_email       => { type => 'CHAR', size => 50, not_null => 1, form_display => 'Email Address', form_regex => $EMAIL_RE },
        ],
        pk => 'stl_id',
        ai => 'stl_id',
        unique => {
            s_e_q => ['stl_email']
        }
    );

    return $output;
}

sub create_table {
    my ($output, $table, $action, @def) = @_;

    $$output .= "Creating $table table ... ";
    my $c = $DB->creator($table);
    $c->clear_schema() if $action eq 'force';

    @def % 2 and die "Odd number of table defs passed to create_table()";
    while (@def) {
        my ($meth, $arg) = splice @def, 0, 2;
        $c->$meth($arg);
    }

    if ($c->create($action)) {
        $$output .= "okay\n";
        return 1;
    }
    else {
        $GT::SQL::errcode if 0; # silence "used only once" warnings
        $$output .= $GT::SQL::errcode eq 'TBLEXISTS' ? "failed (table already exists)\n" : "failed ($GT::SQL::error)\n";
        $c->set_defaults;
        $c->save_schema;
        return 0;
    }
}

sub load_from_sql {
# ---------------------------------------------------------------
# Creates def files based on existing tables.
#
    my ($output, $return);
    foreach my $table (@TABLES) {
        $output .= "$table .. ";
        my $c = $DB->creator($table);
        $return = $c->load_table($table);
        if ($return) {
            $output .= "ok\n";
            $c->save_schema();
        }
        else {
            $output .= "failed: $GT::SQL::error\n";
        }
    }
    return $output;
}

sub load {
# ---------------------------------------------------------------
# Return a hash of current connection settings.
#
    my %h = ();
    $h{prefix}   = $DB->prefix();
    $h{database} = $DB->{connect}->{database};
    $h{login}    = $DB->{connect}->{login};
    $h{password} = $DB->{connect}->{password};
    $h{host}     = $DB->{connect}->{host};
    $h{host}    .= ":" . $DB->{connect}->{port} if $DB->{connect}->{port};
    $h{driver}   = $DB->{connect}->{driver};
    return \%h;
}

1;