adding acct_sql export
[freeside.git] / FS / FS / part_export / acct_sql.pm
1 package FS::part_export::acct_sql;
2
3 use vars qw(@ISA %info @saltset);
4 use Tie::IxHash;
5 #use Digest::MD5 qw(md5_hex);
6 use FS::Record; #qw(qsearchs);
7 use FS::part_export;
8
9 @ISA = qw(FS::part_export);
10
11 tie my %options, 'Tie::IxHash',
12   'datasrc'            => { label => 'DBI data source' },
13   'username'           => { label => 'Database username' },
14   'password'           => { label => 'Database password' },
15 ;
16
17 %info = (
18   'svc'      => 'svc_acct',
19   'desc'     => 'Real-time export of accounts to SQL databases '.
20                 '(Postfix+Courier IMAP, others?)',
21   'options'  => \%options,
22   'nodomain' => '',
23   'notes'    => <<END
24 Export accounts (svc_acct records) to SQL databases.  Written for
25 Postfix+Courier IMAP but intended to be generally useful for generic SQL
26 exports eventually.
27
28 In contrast to sqlmail, this is newer and less well tested, and currently less
29 flexible.  It is intended to export just svc_acct records only, rather than a
30 single export for svc_acct, svc_forward and svc_domain records, and to 
31 be configured for different mail server setups through some subclassing
32 rather than options.
33 END
34 );
35
36 @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
37
38 #mapping needs to be configurable...
39 # export col => freeside col/method or callback
40 my %map = (
41   'username' => 'email',
42   'password' => '_password',
43   'crypt'    => sub {
44                   my $svc_acct = shift;
45                   #false laziness w/shellcommands.pm
46                   #eventually should check a "password-encoding" field
47                   if ( length($svc_acct->_password) == 13
48                        || $svc_acct->_password =~ /^\$(1|2a?)\$/ ) {
49                     $svc_acct->_password;
50                   } else {
51                     crypt(
52                       $svc_acct->_password,
53                       $saltset[int(rand(64))].$saltset[int(rand(64))]
54                     );
55                   }
56
57                 },
58   'name'     => 'finger',
59   'maildir'  => sub { shift->domain. '/maildirs/'. shift->username. '/' },
60   'domain'   => sub { shift->domain },
61   'svcnum'   => 'svcnum',
62 );
63
64 my $table = 'mailbox'; #also needs to be configurable...
65
66 my $primary_key = 'username';
67
68 sub rebless { shift; }
69
70 sub _export_insert {
71   my($self, $svc_acct) = (shift, shift);
72
73
74   my %record = map { my $value = $map{$_};
75                      $_ => ( ref($value)
76                                ? &{$value}($svc_acct)
77                                : $svc_acct->$value()
78                            );
79                    } keys %map;
80
81   my $err_or_queue =
82     $self->acct_sql_queue( $svc_acct->svcnum, 'insert', $table, %record );
83   return $err_or_queue unless ref($err_or_queue);
84
85   '';
86
87 }
88
89 sub _export_replace {
90 }
91
92 sub _export_delete {
93   my ( $self, $svc_acct ) = (shift, shift);
94   my $keymap = $map{$primary_key};
95   my $err_or_queue = $self->acct_sql_queue(
96     $svc_acct->svcnum,
97     'delete',
98     $table,
99     $primary_key => ref($keymap) ? &{$keymap}($svc_acct) : $svc_acct->$keymap()
100   );
101 }
102
103 sub acct_sql_queue {
104   my( $self, $svcnum, $method ) = (shift, shift, shift);
105   my $queue = new FS::queue {
106     'svcnum' => $svcnum,
107     'job'    => "FS::part_export::acct_sql::acct_sql_$method",
108   };
109   $queue->insert(
110     $self->option('datasrc'),
111     $self->option('username'),
112     $self->option('password'),
113     @_,
114   ) or $queue;
115 }
116
117 sub acct_sql_insert { #subroutine, not method
118   my $dbh = acct_sql_connect(shift, shift, shift);
119   my( $table, %record ) = @_;
120
121   my $sth = $dbh->prepare(
122     "INSERT INTO $table ( ". join(", ", keys %record).
123     " ) VALUES ( ". join(", ", map '?', keys %record ). " )"
124   ) or die $dbh->errstr;
125
126   $sth->execute( map $record{$_}, keys %record )
127     or die "can't insert into $table table: ". $sth->errstr;
128
129   $dbh->disconnect;
130 }
131
132 sub acct_sql_connect {
133   #my($datasrc, $username, $password) = @_;
134   #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
135   DBI->connect(@_) or die $DBI::errstr;
136 }
137
138 1;
139
140