440 lines
10 KiB
Perl
440 lines
10 KiB
Perl
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
|
|
use Config::Simple;
|
|
use DBI;
|
|
use File::Basename;
|
|
use POSIX qw(strftime);
|
|
|
|
use SVN::Core;
|
|
use SVN::Repos;
|
|
use SVN::Fs;
|
|
|
|
use Net::LDAP;
|
|
use Net::LDAP qw(LDAP_SUCCESS);
|
|
use URI;
|
|
use Mail::Sendmail;
|
|
|
|
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
|
my $REPOFS = $ARGV[0];
|
|
my $REPOBASE = basename($REPOFS);
|
|
my $REV = $ARGV[1];
|
|
|
|
my $QC = '';
|
|
|
|
sub get_config
|
|
{
|
|
my $cfg = new Config::Simple();
|
|
|
|
if (!$cfg->read ($CFG_FILE))
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
my $config = {
|
|
login_model => $cfg->param ('login_model'),
|
|
|
|
ldap_server_uri => $cfg->param ('ldap_server_uri'),
|
|
ldap_server_protocol_version => $cfg->param ('ldap_server_protocol_version'),
|
|
ldap_auth_mode => $cfg->param ('ldap_auth_mode'),
|
|
ldap_userid_format => $cfg->param ('ldap_userid_format'),
|
|
ldap_password_format => $cfg->param ('ldap_password_format'),
|
|
ldap_admin_binddn => $cfg->param ('ldap_admin_binddn'),
|
|
ldap_admin_password => $cfg->param ('ldap_admin_password'),
|
|
ldap_userid_search_base => $cfg->param ('ldap_userid_search_base'),
|
|
ldap_userid_search_filter => $cfg->param ('ldap_userid_search_filter'),
|
|
ldap_mail_attribute_name => $cfg->param ('ldap_mail_attribute_name'),
|
|
|
|
database_hostname => $cfg->param ("database_hostname"),
|
|
database_port => $cfg->param ("database_port"),
|
|
database_username => $cfg->param ("database_username"),
|
|
database_password => $cfg->param ("database_password"),
|
|
database_name => $cfg->param ("database_name"),
|
|
database_driver => $cfg->param ("database_driver"),
|
|
database_prefix => $cfg->param ("database_prefix"),
|
|
|
|
email_sender => $cfg->param ("email_sender"),
|
|
commit_notification => $cfg->param ("commit_notification"),
|
|
commit_notification_url => $cfg->param ("commit_notification_url")
|
|
};
|
|
|
|
return $config;
|
|
}
|
|
|
|
sub open_database
|
|
{
|
|
my ($cfg) = @_;
|
|
|
|
my $dbtype = $cfg->{database_driver};
|
|
my $dbname = $cfg->{database_name};
|
|
my $dbhost = $cfg->{database_hostname};
|
|
my $dbport = $cfg->{database_port};
|
|
|
|
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
|
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
|
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
|
|
|
my $dbstr;
|
|
my $dbuser;
|
|
my $dbpass;
|
|
if ($dbtype eq 'Oracle')
|
|
{
|
|
$QC = '"';
|
|
$dbstr = "DBI:$dbtype:";
|
|
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
|
$dbpass = '';
|
|
}
|
|
else
|
|
{
|
|
$dbstr = "DBI:$dbtype:database=$dbname;";
|
|
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
|
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
|
|
|
$dbuser = $cfg->{database_username};
|
|
$dbpass = $cfg->{database_password};
|
|
}
|
|
|
|
my $dbh = DBI->connect(
|
|
$dbstr, $dbuser, $dbpass,
|
|
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
|
);
|
|
|
|
return $dbh;
|
|
}
|
|
|
|
sub close_database
|
|
{
|
|
my ($dbh) = @_;
|
|
$dbh->disconnect ();
|
|
}
|
|
|
|
sub write_commit_log
|
|
{
|
|
my ($dbh, $prefix, $projectid, $revision, $userid) = @_;
|
|
|
|
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
|
#| id | type | projectid | message | createdon | action | userid |
|
|
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
|
#| 895 | code | codepot | svn,codepot,72 | 2011-10-10 14:26:43 | commit | hyunghwan.chung |
|
|
|
|
my $message = "svn,$projectid,$revision";
|
|
|
|
|
|
# the PHP side is executing ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS.FF.
|
|
# do i have to do it here or use the database time (CURRENT_TIMESTAMP) instead?
|
|
# make sure that you have the same time between the app server and the data server.
|
|
# to minize side-effect of using the time of data server.
|
|
#my $createdon = strftime ('%Y-%m-%d %H:%M:%S', localtime());
|
|
|
|
$dbh->begin_work ();
|
|
|
|
#my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,?,?,?)");
|
|
#if (!$query || !$query->execute ('code', $projectid, $message, $createdon, 'commit', $userid))
|
|
|
|
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,CURRENT_TIMESTAMP,?,?)");
|
|
if (!$query || !$query->execute ('code', $projectid, $message, 'commit', $userid))
|
|
{
|
|
my $errstr = $dbh->errstr();
|
|
$query->finish ();
|
|
$dbh->rollback ();
|
|
return (-1, $errstr);
|
|
}
|
|
|
|
$query->finish ();
|
|
$dbh->commit ();
|
|
return (0, undef);
|
|
}
|
|
|
|
|
|
sub get_author
|
|
{
|
|
my $pool = SVN::Pool->new(undef);
|
|
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
|
if (!defined($svn))
|
|
{
|
|
print (STDERR "Cannot open svn - $REPOFS\n");
|
|
return undef;
|
|
}
|
|
|
|
my $fs = $svn->fs ();
|
|
if (!defined($fs))
|
|
{
|
|
print (STDERR "Cannot open fs - $REPOFS\n");
|
|
return undef;
|
|
}
|
|
|
|
my $author = $fs->revision_prop ($REV, 'svn:author');
|
|
return $author;
|
|
}
|
|
|
|
sub get_commit_message
|
|
{
|
|
my $pool = SVN::Pool->new(undef);
|
|
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
|
if (!defined($svn))
|
|
{
|
|
print (STDERR "Cannot open svn - $REPOFS\n");
|
|
return undef;
|
|
}
|
|
|
|
my $fs = $svn->fs ();
|
|
if (!defined($fs))
|
|
{
|
|
print (STDERR "Cannot open fs - $REPOFS\n");
|
|
return undef;
|
|
}
|
|
|
|
my $author = $fs->revision_prop ($REV, 'svn:log');
|
|
return $author;
|
|
}
|
|
|
|
|
|
sub format_string
|
|
{
|
|
my ($fmt, $userid, $password) = @_;
|
|
|
|
my $out = $fmt;
|
|
$out =~ s/\$\{userid\}/$userid/g;
|
|
$out =~ s/\$\{password\}/$password/g;
|
|
|
|
return $out;
|
|
}
|
|
|
|
sub get_author_email_ldap
|
|
{
|
|
my ($cfg, $userid) = @_;
|
|
|
|
my $uri = URI->new ($cfg->{ldap_server_uri});
|
|
my $ldap = Net::LDAP->new (
|
|
$uri->host,
|
|
scheme => $uri->scheme,
|
|
port => $uri->port,
|
|
version => $cfg->{ldap_server_protocol_version}
|
|
);
|
|
if (!defined($ldap))
|
|
{
|
|
print (STDERR 'Cannot create LDAP');
|
|
return (-1, undef);
|
|
}
|
|
|
|
my $f_rootdn = format_string ($cfg->{ldap_admin_binddn}, $userid, '');
|
|
my $f_rootpw = format_string ($cfg->{ldap_admin_password}, $userid, '');
|
|
|
|
my $res = $ldap->bind ($f_rootdn, password => $f_rootpw);
|
|
if ($res->code != LDAP_SUCCESS)
|
|
{
|
|
print (STDERR "Cannot bind LDAP as $f_rootdn - " . $res->error());
|
|
$ldap->unbind();
|
|
return (-1, undef);
|
|
}
|
|
|
|
|
|
my $f_basedn = '';
|
|
my $f_filter = '';
|
|
|
|
if ($cfg->{ldap_auth_mode} == 2)
|
|
{
|
|
$f_basedn = format_string ($cfg->{ldap_userid_search_base}, $userid, '');
|
|
$f_filter = format_string ($cfg->{ldap_userid_search_filter}, $userid, '');
|
|
|
|
$res = $ldap->search (base => $f_basedn, scope => 'sub', filter => $f_filter);
|
|
if ($res->code != LDAP_SUCCESS)
|
|
{
|
|
$ldap->unbind();
|
|
return (-1, undef);
|
|
}
|
|
|
|
my $entry = $res->entry(0); # get the first entry only
|
|
if (!defined($entry))
|
|
{
|
|
$ldap->unbind();
|
|
return (0, undef);
|
|
}
|
|
|
|
$f_basedn = $entry->dn ();
|
|
}
|
|
else
|
|
{
|
|
$f_basedn = format_string ($cfg->{ldap_userid_format}, $userid, '');
|
|
}
|
|
|
|
$f_filter = '(' . $cfg->{ldap_mail_attribute_name} . '=*)';
|
|
|
|
$res = $ldap->search (base => $f_basedn, scope => 'sub', filter => $f_filter);
|
|
if ($res->code != LDAP_SUCCESS)
|
|
{
|
|
$ldap->unbind();
|
|
return (0, undef);
|
|
}
|
|
|
|
my $entry = $res->entry(0); # get the first entry only
|
|
if (!defined($entry))
|
|
{
|
|
$ldap->unbind();
|
|
return (0, undef);
|
|
}
|
|
|
|
my $xret = 0;
|
|
my $email = '';
|
|
my @attrs = $entry->attributes ();
|
|
foreach my $attr (@attrs)
|
|
{
|
|
if ($attr eq $cfg->{ldap_mail_attribute_name})
|
|
{
|
|
$email = $entry->get_value ($attr);
|
|
$xret = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
$ldap->unbind();
|
|
return ($xret, $email);
|
|
}
|
|
|
|
sub get_author_email_db
|
|
{
|
|
my ($cfg, $dbh, $prefix, $userid) = @_;
|
|
|
|
my $query = $dbh->prepare ("SELECT ${QC}email${QC} FROM ${QC}${prefix}user_account${QC} WHERE ${QC}userid${QC}=?");
|
|
if (!$query || !$query->execute ($userid))
|
|
{
|
|
return (-1, $dbh->errstr());
|
|
}
|
|
|
|
if (my @row = $query->fetchrow_array())
|
|
{
|
|
return (1, @row[0]);
|
|
}
|
|
|
|
return (0, undef);
|
|
}
|
|
|
|
sub email_message_to_project_members
|
|
{
|
|
my ($cfg, $dbh, $prefix, $projectid, $subject, $message) = @_;
|
|
|
|
my $query = $dbh->prepare ("SELECT ${QC}userid${QC} FROM ${QC}${prefix}project_membership${QC} WHERE ${QC}projectid${QC}=?");
|
|
if (!$query || !$query->execute ($projectid))
|
|
{
|
|
return (-1, $dbh->errstr());
|
|
}
|
|
|
|
my @members;
|
|
while (my @row = $query->fetchrow_array())
|
|
{
|
|
push (@members, $row[0]);
|
|
}
|
|
$query->finish ();
|
|
|
|
my $recipients = '';
|
|
foreach my $member (@members)
|
|
{
|
|
my $xret;
|
|
my $email;
|
|
|
|
if ($cfg->{login_model} eq 'LdapLoginModel')
|
|
{
|
|
($xret, $email) = get_author_email_ldap ($cfg, $member)
|
|
}
|
|
elsif ($cfg->{login_model} eq 'DbLoginModel')
|
|
{
|
|
($xret, $email) = get_author_email_db ($cfg, $dbh, $prefix, $member);
|
|
}
|
|
else
|
|
{
|
|
$xret = -2;
|
|
$email = '';
|
|
}
|
|
|
|
if ($xret >= 1 && defined($email) && length($email) > 0)
|
|
{
|
|
if (length($recipients) > 0) { $recipients .= ', '; }
|
|
$recipients .= $email;
|
|
}
|
|
}
|
|
|
|
if (length($recipients) <= 0) { return (0, undef); }
|
|
|
|
my %mail = (
|
|
To => $recipients,
|
|
Subject => $subject,
|
|
Message => $message
|
|
);
|
|
|
|
if (length($cfg->{email_sender}) > 0)
|
|
{
|
|
$mail{From} .= $cfg->{email_sender};
|
|
}
|
|
|
|
Mail::Sendmail::sendmail (%mail);
|
|
return (1, undef);
|
|
}
|
|
|
|
sub format_commit_url
|
|
{
|
|
my ($fmt, $projectid, $author, $rev) = @_;
|
|
|
|
my $out = $fmt;
|
|
$out =~ s/\$\{PROJECTID\}/$projectid/g;
|
|
$out =~ s/\$\{AUTHOR\}/$author/g;
|
|
$out =~ s/\$\{REV\}/$rev/g;
|
|
|
|
return $out;
|
|
}
|
|
#------------------------------------------------------------
|
|
# MAIN
|
|
#------------------------------------------------------------
|
|
|
|
my $AUTHOR = get_author();
|
|
if (!defined($AUTHOR))
|
|
{
|
|
print (STDERR "Cannot get author for $REPOBASE $REV\n");
|
|
exit (1);
|
|
}
|
|
chomp ($AUTHOR);
|
|
|
|
my $cfg = get_config ();
|
|
if (!defined($cfg))
|
|
{
|
|
print (STDERR "Cannot load codepot configuration file\n");
|
|
exit (1);
|
|
}
|
|
|
|
my $dbh = open_database ($cfg);
|
|
if (!defined($dbh))
|
|
{
|
|
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
|
exit (1);
|
|
}
|
|
|
|
write_commit_log ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $AUTHOR);
|
|
|
|
if (lc($cfg->{commit_notification}) eq 'yes')
|
|
{
|
|
my $commit_subject = "Commit r$REV by $AUTHOR in $REPOBASE";
|
|
my $commit_message = '';
|
|
|
|
if ($cfg->{commit_notification_url} eq '')
|
|
{
|
|
$commit_message = $commit_subject;
|
|
}
|
|
else
|
|
{
|
|
$commit_message = format_commit_url($cfg->{commit_notification_url}, $REPOBASE, $AUTHOR, $REV);
|
|
}
|
|
|
|
my $m = get_commit_message ();
|
|
if (defined($m))
|
|
{
|
|
$commit_message = $commit_message . "\n" . $m;
|
|
}
|
|
|
|
|
|
email_message_to_project_members ($cfg, $dbh, $cfg->{database_prefix}, $REPOBASE, $commit_subject, $commit_message);
|
|
}
|
|
|
|
close_database ($dbh);
|
|
|
|
exit (0);
|