Creates user accounts on SME Server from a limesurvey form
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
7.7 KiB

#!/usr/bin/perl -w
use warnings;
use strict;
use Getopt::Long;
use DBI;
use esmith::ConfigDB;
use esmith::AccountsDB;
use Text::Unaccent::PurePerl qw(unac_string);
use utf8;
my $c = esmith::ConfigDB->open_ro or die "Can't open the configuration DB\n";
my $a = esmith::AccountsDB->open or die "Can't open the accounts DB\n";
my $domain = $c->get('DomainName')->value;
my $limesurvey = $c->get('limesurvey') or die "No limesurvey entry found in the config DB\n";
my $host = 'localhost';
my $dbname = $limesurvey->prop('DbName') || 'limesurvey';
my $dbpass = $limesurvey->prop('DbPassword') || '';
my $dbuser = $limesurvey->prop('DbUser') || 'limesurvey';
my $survey = '889944';
my @notify = ();
my $dry = 0;
my $ok_cnt = 0;
my $ko_cnt = 0;
GetOptions(
'dbname=s' => \$dbname,
'dbuser=s' => \$dbuser,
'dbpassword=s' => \$dbpass,
'survey=s' => \$survey,
'notify=s' => \@notify,
'dry-run' => \$dry
);
# Allow comma separated multi-argument
@notify = split(/,/, join(',', @notify));
if ($survey !~ m/^\d+$/){
die "$survey isn't a valid survey ID\n";
}
my $survey_table = 'survey_' . $survey;
my $new_date = undef;
my $col2field = {
submitdate => 'submitdate',
first_name => '889944X91X1181SQ001',
last_name => '889944X91X1181SQ002',
email => '889944X91X1181SQ003',
phone => '889944X91X1181SQ004',
end_contract => '889944X91X1189',
unit => '889944X90X1191',
unit_other => '889944X90X1191other',
supervisor_name => '889944X90X1190',
supervisor_name_other => '889944X90X1190other',
supervisor_email => '889944X90X1203'
};
my $dsn = "DBI:mysql:database=$dbname;host=localhost";
my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { mysql_enable_utf8 => 1 });
my $last_run;
# Identify last time the script ran
my $sth = $dbh->prepare(
'SELECT submitdate FROM ' . $survey_table . ' WHERE token = \'last_run\'')
or die "prepare statement failed: $dbh->errstr()";
$sth->execute() or die "execution failed: $dbh->errstr()";
if ($sth->rows gt 1){
die "More than one last_run entry found\n";
} elsif ($sth->rows lt 1){
die "Last run not found\n";
}
while (my $ref = $sth->fetchrow_hashref) {
$last_run = $ref->{submitdate};
}
# Query all the submission done after last run
$sth = $dbh->prepare(
'SELECT ' . join(',', map { $col2field->{$_} . ' AS ' . $_ } keys %{$col2field}) . ' FROM ' . $survey_table . ' WHERE submitdate > ?'
) or die "prepare statement failed: $dbh->errstr()";
$sth->execute($last_run);
if ($sth->rows > 0){
print "Last run was $last_run\n";
print "Found " . $sth->rows . " responses to process\n";
}
my $report = '';
while (my $ref = $sth->fetchrow_hashref) {
# Build info for this new user
my $info = {
login => unac_string(lc substr($ref->{first_name}, 0, 1) . lc substr($ref->{last_name},0,12)),
first_name => $ref->{first_name} || '',
last_name => $ref->{last_name} || '',
supervisor_name => $ref->{supervisor_name} || '',
unit => $ref->{unit} || '',
email => $ref->{email} || '',
phone => $ref->{phone} || '',
end_contract => $ref->{end_contract} || '',
};
$info->{login} =~ s/[^\da-z]//g;
foreach (qw(first_name last_name)){
utf8::encode($info->{$_});
}
# Extract email, as it can be in the form "Foo Bar" <foo.bar@baz.org>
$info->{email} = $1 if ($info->{email} =~ m/\<(.+\@.+)\>/);
# Blank out the email if not valid
$info->{email} = '' if not ($info->{email} =~ m/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/);
# Keep only the day for the end of contract
$info->{end_contract} = $1 if ($info->{end_contract} =~ m/^(\d{4}\-\d{1,2}\-\d{1,2})/);
# unit and supervisor can be selected from a dropdown, or entered after selecting "other"
# So we have to do the lookup
my $ansh = $dbh->prepare('SELECT answer FROM answers WHERE code = ? AND qid = ?') or die "prepare statement failed: $dbh->errstr()";
foreach my $field (qw(unit supervisor_name)){
# We have to extract question ID to query the answers table
if ($info->{$field} eq '-oth-'){
$info->{$field} = $ref->{$field . '_other'};
} else {
my $qid = $col2field->{$field};
$qid =~ s/.*(\d{4})$/$1/;
$ansh->execute($ref->{$field},$qid);
if ($ansh->rows == 1){
while (my $ansref = $ansh->fetchrow_hashref){
$info->{$field} = $ansref->{answer};
}
}
}
utf8::encode($info->{$field});
}
# Validate data
my $msg = '';
foreach my $field (qw(login first_name last_name email end_contract unit supervisor_name)){
$msg .= "\n$field $info->{$field} contains invalid data\n" if ($info->{$field} !~ m/[\w\-]*/ or length($info->{$field}) > 60);
}
unless (esmith::AccountsDB::validate_account_name($info->{login})){
$msg .= "Created login $info->{login} is invalid\n";
}
if ($a->get($info->{login})){
$msg .= "A user with login $info->{login} already exists\n";
}
$report .= "-----------------------------------------------------------------------\n";
if ($msg ne ''){
$ko_cnt++;
$report .= "An error occured while processing account for $info->{last_name} $info->{first_name}. " .
"The error is : $msg\n";
} else {
# Default expiration is at the end of the current year
if ($info->{end_contract} eq ''){
$info->{end_contract} = (localtime())[5] + 1900 . '-12-31';
}
print "Creating user account $info->{login} ($info->{first_name} $info->{last_name})\n";
if (not $dry){
$a->new_record($info->{login}, {
type => 'user',
FirstName => $info->{first_name},
LastName => $info->{last_name},
Phone => $info->{phone},
Dept => $info->{unit},
Company => 'Univ de Bordeaux',
PasswordSet => 'no',
ForwardAddress => $info->{email},
PreferredMail => $info->{email},
EmailForward => 'forward',
ExpireLockOn => $info->{end_contract},
ExpireAutoReply => 'enabled',
ExpireWarnUser => 'enabled',
ExpireDeleteAfterLock => 7,
MaxBlocks => 5120000,
MaxBlocksSoftLim => 4608000
});
unless ( system("/sbin/e-smith/signal-event", "user-create", $info->{login}) == 0 ){
$report .= "Error occured while creating account $info->{login}, please contact your administrator\n";
$ko_cnt++;
}
}
$ok_cnt++;
$report .= <<_EOF;
New account created (please, review group membership and set a password)
* Login : $info->{login}
* Last name : $info->{last_name}
* First name : $info->{first_name}
* Email : $info->{email}
* Unit : $info->{unit}
* Supervisor : $info->{supervisor_name}
* Expiration date : $info->{end_contract}
_EOF
$report .= "\n\n\n";
}
$new_date = $ref->{submitdate};
}
# Update the last run entry
if (defined $new_date and not $dry){
$sth = $dbh->prepare(
"UPDATE `$survey_table` SET `submitdate` = ? WHERE `token` = 'last_run'")
or die "prepare statement failed: $dbh->errstr()";
$sth->execute($new_date) or die "execution failed: $dbh->errstr()";
}
$sth->finish;
print $report;
if ($ok_cnt > 0 or $ko_cnt > 0){
foreach my $email (@notify){
print "Sending notification to $email\n";
open(QMAIL, "|/var/qmail/bin/qmail-inject -fdo-not-reply\@$domain $email")
|| die "Could not send mail via qmail-inject!\n";
print QMAIL <<EOH_;
To: $email
From: do-not-reply\@$domain
Subject: Account creation report
EOH_
print QMAIL $report;
close QMAIL;
}
}