# ================================================================== # 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;