File Coverage

blib/lib/SVN/Notify/Filter/EmailFlatFileDB.pm
Criterion Covered Total %
statement 12 75 16.0
branch 0 32 0.0
condition n/a
subroutine 4 9 44.4
pod 2 2 100.0
total 18 118 15.2


line stmt bran cond sub pod time code
1             package SVN::Notify::Filter::EmailFlatFileDB;
2              
3 2     2   403430 use warnings;
  2         5  
  2         72  
4 2     2   11 use strict;
  2         4  
  2         65  
5 2     2   66939 use SVN::Notify;
  2         133662  
  2         70  
6 2     2   23 use Carp;
  2         5  
  2         7276  
7              
8              
9             =head1 NAME
10              
11             SVN::Notify::Filter::EmailFlatFileDB - Converts account names to email address based on a flat-file database
12              
13             =head1 VERSION
14              
15             Version 1.01
16              
17             =cut
18              
19             our $VERSION = '1.01';
20              
21             SVN::Notify->register_attributes(
22             account_file => 'account_file=s',
23             account_field => 'account_field=i',
24              
25              
26             );
27              
28             my %allusers; # key=account name, value=array reference to fields from the file
29             my $SPLITCHAR = ':';
30             my $debug = 0;
31              
32             =head1 SYNOPSIS
33              
34             This is intended to work with SVN::Notify, as part of a subversion post-commit hook.
35              
36             svnnotify --repos-path "$1" --revision "$2" ..etc.. \
37             --filter EmailFlatFileDB \
38             --account_file /x/x/x/users.db \
39             --account_field 3
40              
41             with a text file like other UNIX/Apache password files:
42              
43             user1:xxx:xxx:user1@example.com
44             user2:xxx:xxx:user2@example.com
45              
46             =head1 DESCRIPTION
47              
48             This module is a filter for SVN::Notify, which will translate
49             user account names (e.g. "user1") into email address. It does
50             this based on a colon-separated file, like a UNIX passwd file
51             (or more usefully) the AuthUserFile used by Apache. The file
52             path is specified via the --account_file option to the svnnotify
53             script, and the index (zero-based) of the email field is specified via the
54             --account_field option.
55              
56             You can use the module in conjunction with SVN::Notify::Filter::AuthZEmail
57             to completely remove the necessity of passing in --from and --to options
58             to the script. (AuthZEmail will determine the account names for the
59             email recipients, and this module will translate the account names into
60             email addresses.)
61              
62             (This module will remove --to entries that are empty.)
63              
64              
65             =head1 FUNCTIONS
66              
67             =head2 from
68              
69             SVN::Notify filter callback function for the "from" email address.
70             By default, SVN::Notify uses the account name of the commit author.
71             This will translate that into the email address, based upon the
72             value in the database file. Note that the svnnotify --from option
73             can also be used to override the default SVN::Notify behavior, and
74             this filter will not modify an email address if it is passed in.
75              
76             =cut
77              
78             # The first argument is the SVN::Notify object
79             # The second argument is the sender account name or address.
80              
81             sub from {
82 0     0 1   my ($notifier, $from) = @_;
83 0           my $dbfield= $notifier->account_field;
84              
85 0 0         if ($debug) { print "EmailFlatFileDB From: $from ($dbfield)"; }
  0            
86              
87             # load database... I'm not sure if the order of from/to
88             # is always going to be fixed
89 0 0         if (! %allusers) {
90 0           my $dbfile = $notifier->account_file;
91 0           _loadPasswdDb($dbfile,\%allusers,$dbfield);
92 0 0         if ($debug) { _writePasswdDb(\%allusers); }
  0            
93             }
94              
95 0           ($from) = _translateEmails(\%allusers,$dbfield,$from);
96 0 0         if ($debug) { print " translated to: $from\n"; }
  0            
97              
98 0           return $from;
99             }
100              
101             =head2 recipients
102              
103             SVN::Notify filter callback function to determine the email
104             addresses for the email recipients, based upon account names
105             passed to SVN::Notify.
106              
107             Account names will be looked up via the flat-file database, but
108             any email addresses passed in will not be modified. This allows
109             one to enter either account names or email address via the svnnotify
110             --to options. Email addresses are distinguished from account names
111             if there is an '@' in the string. Empty string account names will
112             be discarded. (The SVN::Notify object requires a --to argument,
113             and an empty string account name is a workaround for that, for
114             filters that completely provide the recipient list.)
115              
116             =cut
117              
118              
119             # The first argument is the SVN::Notify object
120             # The second argument is an array reference to the recipients.
121             sub recipients {
122 0     0 1   my ($notifier, $recip) = @_;
123              
124 0           my $dbfield= $notifier->account_field;
125              
126 0 0         if ($debug) { print 'EmailFlatFileDB to: ' . join(',',@$recip) . "\n"; }
  0            
127              
128             # if the file hasn't been loaded yet, do so
129 0 0         if (! %allusers) {
130 0           my $dbfile = $notifier->account_file;
131 0           _loadPasswdDb($dbfile,\%allusers,$dbfield);
132 0 0         if ($debug) { _writePasswdDb(\%allusers); }
  0            
133             }
134              
135 0           @$recip = _translateEmails(\%allusers,$dbfield,@$recip);
136              
137 0           return $recip;
138             }
139              
140             =head1 AUTHOR
141              
142             Jeffrey Borlik, C<< >>
143              
144             =head1 BUGS
145              
146             Please report any bugs or feature requests to C, or through
147             the web interface at L. I will be notified, and then you'll
148             automatically be notified of progress on your bug as I make changes.
149              
150              
151              
152              
153             =head1 SUPPORT
154              
155             You can find documentation for this module with the perldoc command.
156              
157             perldoc SVN::Notify::Filter::EmailFlatFileDB
158              
159              
160             You can also look for information at:
161              
162             =over 4
163              
164             =item * RT: CPAN's request tracker
165              
166             L
167              
168             =item * AnnoCPAN: Annotated CPAN documentation
169              
170             L
171              
172             =item * CPAN Ratings
173              
174             L
175              
176             =item * Search CPAN
177              
178             L
179              
180             =back
181              
182              
183             =head1 ACKNOWLEDGEMENTS
184              
185             Thanks to David E. Wheeler for SVN::Notify, a very useful tool for Subversion.
186              
187              
188             =head1 COPYRIGHT & LICENSE
189              
190             Copyright 2008 Jeffrey Borlik, all rights reserved.
191              
192             This program is free software; you can redistribute it and/or modify it
193             under the same terms as Perl itself.
194              
195              
196             =cut
197              
198              
199             #################################################################
200             #
201             # Helper functions
202             #
203              
204             sub _loadPasswdDb {
205 0     0     my $passwd_file = shift;
206 0           my $db = shift; # this is a hash (key=username, val=array [user fields])
207 0           my $maxfields = shift; # number of fields needed to store
208              
209 0 0         open (INFILE, $passwd_file) or croak "Can't open email/account file $passwd_file: $!";
210              
211 0           while () {
212 0           chomp;
213 0 0         if (/^\w*$/) { next; } # all whitespace
  0            
214 0 0         if (/^\w*#/) { next; } # hash is a comment
  0            
215              
216 0           my @line = split($SPLITCHAR);
217 0           $#line = $maxfields; # Only keep the number of fields needed
218 0           $$db{lc(shift(@line))} = \@line;
219             }
220              
221 0           close INFILE;
222             }
223              
224             sub _writePasswdDb {
225 0     0     my %db = %{shift(@_)};
  0            
226              
227 0           print "EmailFlatFileDB: Users in DB......\n";
228 0           for my $user (keys(%db)) {
229 0           my $attrs = $db{$user};
230 0           print " $user: " . join('|',@$attrs) . "\n";
231             }
232             }
233              
234             # Uses the hash of user information to return a list of
235             # email addresses, given a list of usernames. Note that the
236             # two arrays are not necessarily of the same size, as users
237             # that are not in the db are dropped.
238              
239             sub _translateEmails {
240 0     0     my $allusers = shift; # users hash
241 0           my $emailfield = shift; # index of the email field
242             # the rest of the arguments are the actual users
243              
244 0           my @emails = ();
245              
246 0           for my $thisuser (@_) {
247 0           $thisuser = lc($thisuser);
248 0 0         if (length($thisuser)==0) {
249             # no accountname
250 0           next;
251             }
252 0 0         if ($thisuser =~ /@/) {
253 0 0         if ($debug >=2) { print "EmailFlatFileDB: $thisuser is already an email address\n"; }
  0            
254 0           push(@emails,$thisuser);
255 0           next;
256             }
257 0 0         if (exists($$allusers{$thisuser})) {
258 0 0         if ($debug >= 2) { print "EmailFlatFileDB: found $thisuser / " . $$allusers{$thisuser}[$emailfield-1]; }
  0            
259 0           push(@emails, $$allusers{$thisuser}[$emailfield-1]);
260             } else {
261 0 0         if ($debug) { print "Skipping $thisuser as there is no email record for them.\n"; }
  0            
262             }
263             }
264              
265 0           return @emails;
266             }
267              
268             1; # End of SVN::Notify::Filter::EmailFlatFileDB