Commit 477205fe authored by sikeda's avatar sikeda
Browse files

[dev] Introducing Sympa::Spool::Requset class for spool keeping requests...

[dev] Introducing Sympa::Spool::Requset class for spool keeping requests waiting for moderation and Sympa::Request class to represent requests.
Additionally, file names have to be "date,listname@domain_authkey,email,action".  Older format will be upgraded during upgrading process.


git-svn-id: https://subversion.renater.fr/sympa/branches/sympa-6.2-branch@12435 05aa8bb8-cd2b-0410-b1d7-8918dfa770ce
parent 33309b17
......@@ -39,7 +39,7 @@ use DateTime;
use DateTime::Format::Mail;
use Digest::MD5;
use Encode qw();
use English; # FIXME: drop $PREMATCH usage
use English qw(-no_match_vars);
use MIME::EncWords;
use MIME::Lite::HTML;
use POSIX qw();
......@@ -68,6 +68,7 @@ use Sympa::Marc::Search;
use Sympa::Message;
use Sympa::Regexps;
use Sympa::Report;
use Sympa::Request;
use Sympa::Robot;
use Sympa::Scenario;
use Sympa::Session;
......@@ -76,6 +77,7 @@ use Sympa::Spool::Archive;
use Sympa::Spool::Held;
use Sympa::Spool::Incoming;
use Sympa::Spool::Moderation;
use Sympa::Spool::Request;
use Sympa::Template;
use tools;
use Sympa::Tools::Data;
......@@ -3084,8 +3086,10 @@ sub check_param_in {
if ($param->{'is_priv'}) {
$param->{'mod_message'} =
Sympa::Spool::Moderation->new(context => $list)->size;
$param->{'mod_subscription'} =
$list->get_subscription_request_count();
$param->{'mod_subscription'} = Sympa::Spool::Request->new(
context => $list,
action => 'add'
)->size;
 
$param->{'doc_mod_list'} = $list->get_shared_moderated();
$param->{'mod_total_shared'} = $#{$param->{'doc_mod_list'}} + 1;
......@@ -5598,10 +5602,8 @@ sub do_set {
my $xml_custom_attribute;
if ($in{custom_attribute}) {
return undef if (check_custom_attribute() != 1);
my $xml = Sympa::Tools::Data::encode_custom_attribute(
$xml_custom_attribute = Sympa::Tools::Data::encode_custom_attribute(
$in{custom_attribute});
$xml_custom_attribute = $xml;
}
 
if ($in{'email'}) {
......@@ -5978,9 +5980,9 @@ sub do_subscribe {
wwslog('notice', "Missing required custom attributes");
return 'subrequest';
}
my $xml = Sympa::Tools::Data::encode_custom_attribute(
$xml_custom_attribute =
Sympa::Tools::Data::encode_custom_attribute(
$in{custom_attribute});
$xml_custom_attribute = $xml;
}
 
if ($param->{'is_subscriber'}) {
......@@ -6028,7 +6030,6 @@ sub do_subscribe {
$param->{'may_subscribe'} = 1;
 
if ($sub_is =~ /owner/) {
$list->send_notify_to_owner(
'subrequest',
{ 'who' => $param->{'user'}{'email'},
......@@ -6042,8 +6043,15 @@ sub do_subscribe {
}
);
 
$list->store_subscription_request($param->{'user'}{'email'},
"", $xml_custom_attribute);
my $spool_req = Sympa::Spool::Request->new;
my $request = Sympa::Request->new_from_tuples(
context => $list,
sender => $param->{'user'}{'email'},
custom_attribute => $in{custom_attribute},
action => 'add'
);
$spool_req->store($request);
Sympa::Report::notice_report_web('sent_to_owner', {},
$param->{'action'});
wwslog('info', 'Subscribe sent to owners');
......@@ -7997,7 +8005,6 @@ sub do_add_request {
## TODO: vérifier validité email
sub do_add {
wwslog('info', '(%s)', $in{'email'} || $in{'pending_email'});
my $subscriptions = $list->get_subscription_requests();
 
my %user;
 
......@@ -8060,17 +8067,6 @@ sub do_add {
my ($total, @new_users, @added_users);
my $comma_emails;
foreach my $email (keys %user) {
wwslog('debug',
"do_add subscription \$subscriptions->{$email}{custom_attribute} = $subscriptions->{$email}{'custom_attribute'})"
);
if (ref($subscriptions->{$email}{'custom_attribute'}) eq 'HASH') {
my $xml = Sympa::Tools::Data::encode_custom_attribute(
$subscriptions->{$email}{'custom_attribute'});
wwslog('debug',
"do_add subscription XML \$subscriptions->{$email}{custom_attribute} = $xml;"
);
}
my $result = Sympa::Scenario::request_action(
$list, 'add',
$param->{'auth_method'},
......@@ -8203,8 +8199,18 @@ sub do_add {
return 'info';
}
 
## Delete subscription request if any
$list->delete_subscription_request(@added_users);
# Delete subscription requests if any
my $spool_req =
Sympa::Spool::Request->new(context => $list, action => 'add');
while (1) {
my ($request, $handle) = $spool_req->next;
last unless $handle;
next
unless $request
and grep { $request->{sender} eq $_ } @added_users;
$spool_req->remove($handle);
}
 
Sympa::Report::notice_report_web('add_performed', {'total' => $total},
$param->{'action'});
......@@ -11236,8 +11242,10 @@ sub do_home {
$mod_message
if $mod_message;
 
my $mod_subscription =
$one_list->get_subscription_request_count();
my $mod_subscription = Sympa::Spool::Request->new(
context => $one_list,
action => 'add'
)->size;
$param->{'admin_summary'}{$one_list->{'name'}}
{'mod_subscription'} = $mod_subscription
if $mod_subscription;
......@@ -22105,14 +22113,25 @@ sub do_attach {
sub do_subindex {
wwslog('info', '');
 
my $subscriptions = $list->get_subscription_requests();
foreach my $sub (keys %{$subscriptions}) {
$subscriptions->{$sub}{'date'} =
$language->gettext_strftime("%d %b %Y",
localtime($subscriptions->{$sub}{'date'}));
}
my $spool_req =
Sympa::Spool::Request->new(context => $list, action => 'add');
my $subscriptions;
while (1) {
my ($request, $handle) = $spool_req->next(no_lock => 1);
last unless $handle;
next unless $request;
 
$subscriptions->{$request->{sender}} = {
custom_attribute => $request->{custom_attribute},
date => $language->gettext_strftime(
'%d %b %Y', localtime $request->{date}
),
epoch => $request->{date},
gecos => $request->{gecos},
};
}
$param->{'subscriptions'} = $subscriptions;
web_db_log(
{ 'robot' => $robot,
'list' => $list->{'name'},
......@@ -22134,32 +22153,21 @@ sub do_ignoresub {
my @users;
 
foreach my $pair (split /\0/, $in{'pending_email'}) {
if ($pair =~ /,/) {
push @users, $PREMATCH;
if ($pair =~ /\A([^,]+),/) {
push @users, $1;
}
}
 
foreach my $u (@users) {
unless ($list->delete_subscription_request($u)) {
Sympa::Report::reject_report_web('intern', 'del_sub_request',
{'sub' => $u},
$param->{'action'}, $list, $param->{'user'}{'email'}, $robot);
wwslog('info', '(%s) Failed', $u);
web_db_log(
{ 'robot' => $robot,
'list' => $list->{'name'},
'action' => $param->{'action'},
'parameters' => "",
'target_email' => "",
'msg_id' => '',
'status' => 'error',
'error_type' => 'internal',
'user_email' => $param->{'user'}{'email'},
}
);
return 'subindex';
}
my $spool_req =
Sympa::Spool::Request->new(context => $list, action => 'add');
while (1) {
my ($request, $handle) = $spool_req->next;
last unless $handle;
next unless $request and grep { $request->{sender} eq $_ } @users;
$spool_req->remove($handle);
}
web_db_log(
{ 'robot' => $robot,
'list' => $list->{'name'},
......
......@@ -799,7 +799,7 @@ sub checkfiles {
}
}
foreach my $qdir (qw(spool queuetopic queuesubscribe queuetask tmpdir)) {
foreach my $qdir (qw(spool queuetopic queuetask tmpdir)) {
unless (-d $Conf{$qdir}) {
$log->syslog('info', 'Creating spool %s', $Conf{$qdir});
unless (mkdir($Conf{$qdir}, 0775)) {
......@@ -843,8 +843,7 @@ sub checkfiles {
queuetopic spool tmpdir viewmail_dir);
push @keys, 'queueautomatic'
if $Conf::Conf{'automatic_list_feature'} eq 'on';
my %dirs = (Sympa::Constants::PIDDIR() => 'PID directory',
);
my %dirs = (Sympa::Constants::PIDDIR() => 'PID directory');
foreach my $key (@keys) {
my $val = $Conf::Conf{$key};
......@@ -2142,8 +2141,9 @@ sub _detect_missing_mandatory_parameters {
next;
}
unless (defined $param->{'config_hash'}{$parameter}) {
$param->{'config_hash'}{$parameter} = $params{$parameter}->{'default'};
}
$param->{'config_hash'}{$parameter} =
$params{$parameter}->{'default'};
}
}
return $number_of_errors;
}
......
......@@ -68,6 +68,7 @@ nobase_modules_DATA = \
Sympa/ModDef.pm \
Sympa/Regexps.pm \
Sympa/Report.pm \
Sympa/Request.pm \
Sympa/Robot.pm \
Sympa/Scenario.pm \
SDM.pm \
......@@ -84,6 +85,7 @@ nobase_modules_DATA = \
Sympa/Spool/Held.pm \
Sympa/Spool/Incoming.pm \
Sympa/Spool/Moderation.pm \
Sympa/Spool/Request.pm \
Sympa/Task.pm \
Sympa/Template.pm \
tools.pm \
......
......@@ -35,9 +35,11 @@ use Sympa::List;
use Sympa::Log;
use Sympa::Regexps;
use Sympa::Report;
use Sympa::Request;
use Sympa::Scenario;
use Sympa::Spool::Held;
use Sympa::Spool::Moderation;
use Sympa::Spool::Request;
use Sympa::Tools::Data;
use Sympa::Tools::File;
use Sympa::Tools::Password;
......@@ -1194,7 +1196,16 @@ sub subscribe {
$robot
);
}
if ($list->store_subscription_request($sender, $comment)) {
my $spool_req = Sympa::Spool::Request->new;
my $request = Sympa::Request->new_from_tuples(
context => $list,
sender => $sender,
gecos => $comment,
action => 'add',
date => $message->{date}, # Keep date of message.
);
if ($spool_req->store($request)) {
$log->syslog(
'info',
'SUB %s from %s forwarded to the owners of the list (%d seconds)',
......@@ -1869,7 +1880,19 @@ sub add {
return undef;
}
$list->delete_subscription_request($email);
my $spool_req = Sympa::Spool::Request->new(
context => $list,
sender => $email,
action => 'add'
);
while (1) {
my ($request, $handle) = $spool_req->next;
last unless $handle;
next unless $request;
$spool_req->remove($handle);
}
Sympa::Report::notice_report_cmd('now_subscriber',
{'email' => $email, 'listname' => $which}, $cmd_line);
}
......
......@@ -65,6 +65,7 @@ use Sympa::Spool::Archive;
use Sympa::Spool::Digest;
use Sympa::Spool::Held;
use Sympa::Spool::Moderation;
use Sympa::Spool::Request;
use Sympa::Task;
use Sympa::Template;
use tools;
......@@ -5025,9 +5026,21 @@ sub add_list_member {
$self->{'add_outcome'}{'remaining_members_to_add'} =
$self->{'add_outcome'}{'expected_number_of_added_users'};
my $subscriptions = $self->get_subscription_requests();
my $current_list_members_count = $self->get_total();
my $subscriptions;
my $spool_req =
Sympa::Spool::Request->new(context => $self, action => 'add');
while (1) {
my ($request, $handle) = $spool_req->next(no_lock => 1);
last unless $handle;
next
unless $request
and grep { $request->{sender} eq $_->{email} } @new_users;
$subscriptions->{$request->{sender}} = $request;
}
foreach my $new_user (@new_users) {
my $who = Sympa::Tools::Text::canonic_email($new_user->{'email'});
unless (defined $who) {
......@@ -7449,8 +7462,9 @@ sub _load_list_admin_from_include {
bind_password => $incl->{'passwd'},
);
$included =
_include_users_ldap(\%admin_users, Sympa::Datasource::_get_datasource_id($incl), $incl, $db,
\%option);
_include_users_ldap(\%admin_users,
Sympa::Datasource::_get_datasource_id($incl),
$incl, $db, \%option);
} elsif ($type eq 'include_ldap_2level_query') {
my $db = Sympa::Database->new(
'LDAP',
......@@ -7460,7 +7474,8 @@ sub _load_list_admin_from_include {
timeout => $incl->{'timeout1'}, # Note: not "timeout"
);
my $result =
_include_users_ldap_2level(\%admin_users, Sympa::Datasource::_get_datasource_id($incl),
_include_users_ldap_2level(\%admin_users,
Sympa::Datasource::_get_datasource_id($incl),
$incl, $db, \%option);
if (defined $result) {
$included = $result->{'total'};
......@@ -10579,224 +10594,17 @@ sub select_list_members_for_topic {
#
### END - functions for message topics ###
sub store_subscription_request {
my ($self, $email, $gecos, $custom_attr) = @_;
$log->syslog('debug2', '(%s, %s, %s)', $self->{'name'}, $email, $gecos,
$custom_attr);
my $filename =
$Conf::Conf{'queuesubscribe'} . '/'
. $self->get_list_id() . '.'
. time . '.'
. int(rand(1000));
unless (opendir SUBSPOOL, "$Conf::Conf{'queuesubscribe'}") {
$log->syslog(
'err',
'Could not open %s',
$Conf::Conf{'queuesubscribe'}
);
return undef;
}
my @req_files = sort grep (!/^\.+$/, readdir(SUBSPOOL));
closedir SUBSPOOL;
my $listaddr = $self->get_list_id();
foreach my $file (@req_files) {
next unless ($file =~ /$listaddr\..*/);
unless (open OLDREQUEST, "$Conf::Conf{'queuesubscribe'}/$file") {
$log->syslog('err', 'Could not open %s for verification', $file);
return undef;
}
foreach my $line (<OLDREQUEST>) {
if ($line =~ /^$email/i) {
$log->syslog('notice', 'Subscription already requested by %s',
$email);
return undef;
}
}
close OLDREQUEST;
}
unless (open REQUEST, ">$filename") {
$log->syslog('notice', 'Could not open %s', $filename);
return undef;
}
## First line of the file contains the user email address + his/her name
printf REQUEST "%s\t%s\n", $email, (defined $gecos ? $gecos : '');
# DEPRECATED. Use Sympa::Spool::Request::store().
#sub store_subscription_request;
## Following lines may contain custom attributes in an XML format
printf REQUEST "%s\n", $custom_attr if defined $custom_attr;
# DEPRECATED. Use Sympa::Spool::Request::next().
#sub get_subscription_requests;
close REQUEST;
# DEPRECATED. Use Sympa::Spool::Request::size().
#sub get_subscription_request_count;
return 1;
}
sub get_subscription_requests {
my ($self) = shift;
$log->syslog('debug2', '(%s)', $self->{'name'});
my %subscriptions;
unless (opendir SPOOL, $Conf::Conf{'queuesubscribe'}) {
$log->syslog(
'info',
'Unable to read spool %s',
$Conf::Conf{'queuesubscribe'}
);
return undef;
}
foreach my $filename (
sort grep(/^$self->{'name'}(\@$self->{'domain'})?\.\d+\.\d+$/,
readdir SPOOL)
) {
my $fh; #FIXME: files should be locked.
unless (open $fh, '<', "$Conf::Conf{'queuesubscribe'}/$filename") {
$log->syslog('err', 'Could not open %s', $filename);
closedir SPOOL;
next;
}
## First line of the file contains the user email address + his/her
## name
my $line = <$fh>;
my ($email, $gecos);
if ($line =~ /^((\S+|\".*\")\@\S+)\s*([^\t]*)\t(.*)$/) {
($email, $gecos) = ($1, $3);
} else {
$log->syslog('err', "Failed to parse subscription request %s",
$filename);
next;
}
my $user_entry = $self->get_list_member($email, probe => 1);
if ($user_entry and $user_entry->{'subscribed'}) {
$log->syslog(
'err',
'User %s is subscribed to %s already. Deleting subscription request',
$email,
$self->{'name'}
);
unless (unlink "$Conf::Conf{'queuesubscribe'}/$filename") {
$log->syslog('err', 'Could not delete file %s', $filename);
}
next;
}
## Following lines may contain custom attributes in an XML format
my $custom_attribute = do { local $RS; <$fh> };
close $fh;
my $xml =
Sympa::Tools::Data::decode_custom_attribute($custom_attribute);
$subscriptions{$email} = {
'gecos' => $gecos,
'custom_attribute' => $xml
};
unless ($subscriptions{$email}{'gecos'}) {
my $user = Sympa::User->new($email);
if ($user->gecos) {
$subscriptions{$email}{'gecos'} = $user->gecos;
}
}
$filename =~ /^$self->{'name'}(\@$self->{'domain'})?\.(\d+)\.\d+$/;
$subscriptions{$email}{'date'} = $2;
}
closedir SPOOL;
return \%subscriptions;
}
sub get_subscription_request_count {
my ($self) = shift;
$log->syslog('debug2', '(%s)', $self->{'name'});
my %subscriptions;
my $i = 0;
unless (opendir SPOOL, $Conf::Conf{'queuesubscribe'}) {
$log->syslog(
'info',
'Unable to read spool %s',
$Conf::Conf{'queuesubscribe'}
);
return undef;
}
foreach my $filename (
sort grep(/^$self->{'name'}(\@$self->{'domain'})?\.\d+\.\d+$/,
readdir SPOOL)
) {
$i++;
}
closedir SPOOL;
return $i;
}
sub delete_subscription_request {
my ($self, @list_of_email) = @_;
$log->syslog('debug2', '(%s, %s)', $self->{'name'},
join(',', @list_of_email));
my $removed_file = 0;
my $email_regexp = Sympa::Regexps::email();
unless (opendir SPOOL, $Conf::Conf{'queuesubscribe'}) {
$log->syslog(
'info',
'Unable to read spool %s',
$Conf::Conf{'queuesubscribe'}
);
return undef;
}
foreach my $filename (
sort grep(/^$self->{'name'}(\@$self->{'domain'})?\.\d+\.\d+$/,
readdir SPOOL)
) {
unless (open REQUEST, "$Conf::Conf{'queuesubscribe'}/$filename") {
$log->syslog('notice', 'Could not open %s', $filename);
next;
}
my $line = <REQUEST>;
close REQUEST;
foreach my $email (@list_of_email) {
unless ($line =~ /^($email_regexp)\s*/ && ($1 eq $email)) {
next;
}
unless (unlink "$Conf::Conf{'queuesubscribe'}/$filename") {
$log->syslog('err', 'Could not delete file %s', $filename);
last;
}
$removed_file++;
}
}
closedir SPOOL;
unless ($removed_file > 0) {
$log->syslog(
'debug2',
'No pending subscription was found for users %s',
join(',', @list_of_email)
);
return undef;
}
return 1;
}
# DEPRECATED. Use Sympa::Spool::Request::remove().
#sub delete_subscription_request;
sub get_shared_size {
my $self = shift;
......
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015 GIP RENATER
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
package Sympa::Request;
use strict;
use warnings;
use Scalar::Util qw();
use Sympa::Log;
use Sympa::Tools::Data;
use Sympa::Tools::Text;
use Sympa::User;
my $log = Sympa::Log->instance;
sub new {
my $class = shift;
my $serialized = shift;
my $self = bless {@_} => $class;
$self->{sender} = Sympa::Tools::Text::canonic_email($self->{sender})
if defined $self->{sender};
# Get attributes from pseudo-header fields at the top of serialized