Commit a07bf80e authored by sikeda's avatar sikeda
Browse files

[dev] Refactoring. Introducing Sympa::Request::Handler to be base class of request handlers.

ToDo: Regression test.


git-svn-id: https://subversion.renater.fr/sympa/branches/sympa-6.2-branch@12753 05aa8bb8-cd2b-0410-b1d7-8918dfa770ce
parent 579360f3
......@@ -74,6 +74,7 @@ nobase_modules_DATA = \
Sympa/Regexps.pm \
Sympa/Report.pm \
Sympa/Request.pm \
Sympa/Request/Handler.pm \
Sympa/Request/Handler/add.pm \
Sympa/Request/Handler/auth.pm \
Sympa/Request/Handler/confirm.pm \
......
......@@ -37,9 +37,6 @@ our %comms = (
arg_regexp => qr{(\S+)\s+($_email_re)(?:\s+(.+))?\s*\z},
arg_keys => [qw(localpart email gecos)],
cmd_format => 'ADD %s %s %s',
ctx_class => 'Sympa::List',
scenario => 'add',
action_regexp => qr'reject|request_auth|do_it'i,
},
auth => {
cmd_regexp => qr'auth'i,
......@@ -58,26 +55,18 @@ our %comms = (
arg_regexp => qr{(\S+)\s+($_email_re)\s*},
arg_keys => [qw(localpart email)],
cmd_format => 'DEL %s %s',
ctx_class => 'Sympa::List',
scenario => 'del',
action_regexp => qr'reject|request_auth|do_it'i,
},
distribute => {
cmd_regexp => qr'dis|distribute'i,
arg_regexp => qr'(\S+)\s+(\w+)\s*\z',
arg_keys => [qw(localpart authkey)],
cmd_format => 'DISTRIBUTE %s %s',
ctx_class => 'Sympa::List',
# No scenario.
},
get => {
cmd_regexp => qr'get'i,
arg_regexp => qr'(\S+)\s+(.+)',
arg_keys => [qw(localpart arc)],
cmd_format => 'GET %s %s',
ctx_class => 'Sympa::List',
scenario => 'archive.mail_access',
action_regexp => qr'reject|do_it'i,
},
help => {cmd_regexp => qr'hel|help|sos'i, cmd_format => 'HELP',},
info => {
......@@ -85,36 +74,24 @@ our %comms = (
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'INFO %s',
ctx_class => 'Sympa::List',
scenario => 'info',
action_regexp => qr'reject|do_it'i,
},
index => {
cmd_regexp => qr'ind|index'i,
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'INDEX %s',
ctx_class => 'Sympa::List',
scenario => 'archive.mail_access',
action_regexp => qr'reject|do_it'i,
},
invite => {
cmd_regexp => qr'inv|invite'i,
arg_regexp => qr{(\S+)\s+($_email_re)(?:\s+(.+))?\s*\z},
arg_keys => [qw(localpart email gecos)],
cmd_format => 'INVITE %s %s %s',
ctx_class => 'Sympa::List',
scenario => 'invite',
action_regexp => qr'reject|request_auth|do_it'i,
},
last => {
cmd_regexp => qr'las|last'i,
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'LAST %s',
ctx_class => 'Sympa::List',
scenario => 'archive.mail_access',
action_regexp => qr'reject|do_it'i,
},
lists => {cmd_regexp => qr'lis|lists?'i, cmd_format => 'LISTS',},
modindex => {
......@@ -122,8 +99,6 @@ our %comms = (
arg_regexp => qr'(\S+)',
arg_keys => [qw(localpart)],
cmd_format => 'MODINDEX %s',
ctx_class => 'Sympa::List',
# No scenario. Only actual editors are allowed.
},
finished => {cmd_regexp => qr'qui|quit|end|stop|-'i,},
reject => {
......@@ -131,8 +106,6 @@ our %comms = (
arg_regexp => qr'(\S+)\s+(\w+)\s*\z',
arg_keys => [qw(localpart authkey)],
cmd_format => 'REJECT %s %s',
ctx_class => 'Sympa::List',
# No scenario.
},
remind => {
cmd_regexp => qr'rem|remind'i,
......@@ -153,24 +126,16 @@ our %comms = (
}
$r;
},
ctx_class => 'Sympa::List',
scenario => 'remind',
action_regexp => qr'reject|request_auth|do_it'i,
},
global_remind => {
cmd_regexp => qr'(?:rem|remind)\s+[*]'i,
cmd_format => 'REMIND *',
scenario => 'global_remind',
action_regexp => qr'reject|request_auth|do_it'i,
},
review => {
cmd_regexp => qr'rev|review|who'i,
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'REVIEW %s',
ctx_class => 'Sympa::List',
scenario => 'review',
action_regexp => qr'reject|request_auth|do_it'i,
},
set => {
cmd_regexp => qr'set'i,
......@@ -194,8 +159,6 @@ our %comms = (
}
$r;
},
ctx_class => 'Sympa::List',
# No scenario. Only list members are allowed.
},
global_set => {
cmd_regexp => qr'set\s+[*]'i,
......@@ -225,9 +188,6 @@ our %comms = (
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'STATS %s',
ctx_class => 'Sympa::List',
scenario => 'review',
action_regexp => qr'reject|do_it'i, #FIXME: request_auth?
},
subscribe => {
cmd_regexp => qr'sub|subscribe'i,
......@@ -239,9 +199,6 @@ our %comms = (
$r->{email} = $r->{sender};
$r;
},
ctx_class => 'Sympa::List',
scenario => 'subscribe',
action_regexp => qr'reject|request_auth|owner|do_it'i,
},
signoff => {
cmd_regexp => qr'sig|signoff|uns|unsub|unsubscribe'i,
......@@ -271,9 +228,6 @@ our %comms = (
}
$r;
},
ctx_class => 'Sympa::List',
scenario => 'unsubscribe',
action_regexp => qr'reject|request_auth|owner|do_it'i,
},
global_signoff => {
cmd_regexp => qr'(?:sig|signoff|uns|unsub|unsubscribe)\s+[*]'i,
......@@ -299,8 +253,6 @@ our %comms = (
arg_regexp => qr'(.+)',
arg_keys => [qw(localpart)],
cmd_format => 'VERIFY %s',
ctx_class => 'Sympa::List',
# No scenario.
},
which => {cmd_regexp => qr'whi|which|status'i, cmd_format => 'WHICH',},
);
......@@ -320,11 +272,63 @@ TBD
=head1 DESCRIPTION
TBD
This module keeps definition of mail commands.
=head2 Global variable
=over
=item %comms
This hash defines format of mail commands.
It is used for decoding and encoding between command lines and internal
request objects.
Key is the name of action which is given as C<action> parameter to constructor
of L<Sympa::Request>.
Note that not all sort of requests are defined.
Value is the hashref.
Each item of hashrefs accepts the following keywords :
=over
=item cmd_regexp
A regexp matching command.
Note that C<i> modifier is necessary.
=item arg_regexp
A regexp matching command line arguments.
Note that C<i> modifier may be needed.
=item arg_keys
An arrayref of parameter names mapping command line to attribute.
C<'localpart'> is special:
If it is contained, C<context> attribute of resulting request object is
an instance of L<Sympa::List> class.
=item cmd_format
A string to format command line using attributes.
If this item is code reference, it will be called with request object
and returned value will be used as format string.
=item filter
A coderef to perform additional checking.
It is called with request object and, if it returns false value,
decoding will fail.
=back
=back
=head1 SEE ALSO
L<Sympa::Request::Message>.
L<Sympa::Request>, L<Sympa::Request::Message>.
=head1 HISTORY
......
......@@ -86,6 +86,8 @@ workflow of Sympa. For more details see documentation on each class.
: / \---> [ToAuthOwner] => Auth
Auth => [ProcessAuth] ------+ \
+-> [DispatchRequest]
\
(request handler)
:
*3
......@@ -140,6 +142,10 @@ L<Sympa::Message::Template> class.
L<Sympa::Request::Message> class.
=item C<(request handler)>
A subclass of C<Sympa::Request::Handler> class.
=back
=head1 SEE ALSO
......
......@@ -26,6 +26,7 @@ package Sympa::Request;
use strict;
use warnings;
use English qw(-no_match_vars);
use Scalar::Util qw();
use Sympa;
......@@ -53,8 +54,19 @@ sub new {
} else {
$serialized = shift;
}
my %options = @_;
my $handler = $options{action};
$handler = 'Sympa::Request::Handler::' . $handler
unless 0 < index $handler, '::';
unless (eval sprintf 'require %s',
$handler and $handler->isa('Sympa::Request::Handler')) {
$log->syslog('err', 'Unable to use %s module: %s',
$handler, $EVAL_ERROR || 'Not a Sympa::Request::Handler class');
return undef;
}
my $self = bless {@_} => $class;
my $self = bless {%options, _handler => $handler} => $class;
$self->{email} = Sympa::Tools::Text::canonic_email($self->{email})
if defined $self->{email};
......@@ -198,19 +210,23 @@ sub _canonic_value {
$val;
}
sub handler {
shift->{_handler};
}
sub get_id {
my $self = shift;
join ';', map {
my $val = $self->{$_};
if (ref $val eq 'Sympa::List') {
if (ref $val) {
sprintf '%s=%s', $_, $val->get_id;
} else {
sprintf '%s=%s', $_, $val;
}
} grep {
defined $self->{$_}
} qw(action context arc email mode error);
} qw(action context arc email reception visibility request error);
}
1;
......@@ -290,6 +306,11 @@ Returns serialized data of object.
I<Instance method>.
TBD.
=item handler ( )
I<Instance method>.
Name of a subclass of L<Sympa::Request::Handler> to process request.
=item get_id ( )
I<Instance method>.
......@@ -340,6 +361,8 @@ See also L<Sympa::Message/"Serialization"> for example.
=head1 SEE ALSO
L<Sympa::Request::Handler>,
L<Sympa::Request::Message>,
L<Sympa::Spool::Auth>.
=head1 HISTORY
......
# -*- 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, 2016 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::Handler;
use strict;
use warnings;
use base qw(Sympa::Spindle);
sub action_regexp {
my $self = shift;
$self->_action_scenario ? $self->_action_regexp : undef;
}
sub action_scenario {
shift->_action_scenario;
}
sub context_class {
shift->_context_class;
}
sub _context_class {''}
sub owner_action {
shift->_owner_action;
}
sub _owner_action {undef}
1;
__END__
=encoding utf-8
=head1 NAME
Sympa::Request::Handler - Base class of request handler classes
=head1 SYNOPSYS
package Sympa::Request::Handler::foo;
use base qw(Sympa::Request::Handler);
use constant _action_regexp => qr{reject|request_auth|do_it}i;
use constant _action_scenario => 'review';
use constant _context_class => 'Sympa::List';
sub _twist {
...
}
1;
=head1 DESCRIPTION
L<Sympa::Request::Handler> is the base class of subclasses to process
instance of L<Sympa::Request>.
=head2 Methods
TBD.
=head2 Methods subclass should implement
=over
=item _action_regexp ( )
I<Instance method>,
I<mandatory> if _action_scenario() returns true value.
Returns a regexp matching available scenario results.
Note that C<i> modifier is necessary.
=item _action_scenario ( )
I<Instance method>,
I<mandatory>.
Returns the name of scenario to authorize the request under given context.
If authorization is not required, returns C<undef>.
=item _context_class ( )
I<Instance method>.
Returns the class name of context under which the request will be executed,
L<Sympa::List> etc.
By default, returns robot context.
=item _owner_action ( )
I<Instance method>.
Returns name of action to be stored in spool when scenario returns C<owner>.
By default, returns C<undef>.
=item _twist ( $request )
I<Instance method>,
I<mandatory>.
See L<Sympa::Spindle/"_twist">.
=back
=head1 SEE ALSO
L<Sympa::Request>, L<Sympa::Spindle>.
=head1 HISTORY
L<Sympa::Request::Handler> appeared on Sympa 6.2.15.
=cut
......@@ -35,11 +35,15 @@ use Sympa::Spool::Auth;
use Sympa::Tools::Password;
use Sympa::User;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $language = Sympa::Language->instance;
my $log = Sympa::Log->instance;
use constant _action_scenario => 'add';
use constant _action_regexp => qr'reject|request_auth|do_it'i;
use constant _context_class => 'Sympa::List';
# Adds a user to a list (requested by another user). Verifies
# the proper authorization and sends acknowledgements unless
# quiet add.
......@@ -48,16 +52,6 @@ sub _twist {
my $self = shift;
my $request = shift;
unless (ref $request->{context} eq 'Sympa::List') {
$self->add_stash($request, 'user', 'unknown_list');
$log->syslog(
'info',
'%s from %s refused, unknown list for robot %s',
uc $request->{action},
$request->{sender}, $request->{context}
);
return 1;
}
my $list = $request->{context};
my $which = $list->{'name'};
my $robot = $list->{'domain'};
......
......@@ -32,10 +32,12 @@ use Sympa;
use Sympa::Log;
use Sympa::Spindle::ProcessAuth;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $log = Sympa::Log->instance;
use constant _action_scenario => undef;
sub _twist {
my $self = shift;
my $request = shift;
......
......@@ -31,10 +31,12 @@ use Time::HiRes qw();
use Sympa::Log;
use Sympa::Spindle::ProcessHeld;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $log = Sympa::Log->instance;
use constant _action_scenario => undef;
# Confirms the authentication of a message for its
# distribution on a list.
# Old name: Sympa::Commands::confirm().
......
......@@ -33,11 +33,15 @@ use Sympa::Language;
use Sympa::Log;
use Sympa::Spool::Auth;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $language = Sympa::Language->instance;
my $log = Sympa::Log->instance;
use constant _action_scenario => 'del';
use constant _action_regexp => qr'reject|request_auth|do_it'i;
use constant _context_class => 'Sympa::List';
# Removes a user from a list (requested by another user).
# Verifies the authorization and sends acknowledgements
# unless quiet is specified.
......@@ -46,16 +50,6 @@ sub _twist {
my $self = shift;
my $request = shift;
unless (ref $request->{context} eq 'Sympa::List') {
$self->add_stash($request, 'user', 'unknown_list');
$log->syslog(
'info',
'%s from %s refused, unknown list for robot %s',
uc $request->{action},
$request->{sender}, $request->{context}
);
return 1;
}
my $list = $request->{context};
my $which = $list->{'name'};
my $robot = $list->{'domain'};
......
......@@ -31,26 +31,19 @@ use Time::HiRes qw();
use Sympa::Log;
use Sympa::Spindle::ProcessModeration;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $log = Sympa::Log->instance;
use constant _action_scenario => undef;
use constant _context_class => 'Sympa::List';
# Distributes the broadcast of a validated moderated message.
# Old name: Sympa::Commands::distribute().
sub _twist {
my $self = shift;
my $request = shift;
unless (ref $request->{context} eq 'Sympa::List') {
$self->add_stash($request, 'user', 'unknown_list');
$log->syslog(
'info',
'%s from %s refused, unknown list for robot %s',
uc $request->{action},
$request->{sender}, $request->{context}
);
return 1;
}
my $list = $request->{context};
my $which = $list->{'name'};
my $robot = $list->{'domain'};
......
......@@ -27,7 +27,9 @@ package Sympa::Request::Handler::finished;
use strict;
use warnings;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
use constant _action_scenario => undef;
# Do not process what is after this line.
# Old name: Sympa::Commands::finished().
......
......@@ -33,27 +33,21 @@ use Sympa::Archive;
use Sympa::Language;
use Sympa::Log;
use base qw(Sympa::Spindle);
use base qw(Sympa::Request::Handler);
my $language = Sympa::Language->instance;
my $log = Sympa::Log->instance;
use constant _action_scenario => 'archive.mail_access';
use constant _action_regexp => qr'reject|do_it'i;
use constant _context_class => 'Sympa::List';
# Sends back the requested archive file.
# Old name: Sympa::Commands::getfile().
sub _twist {
my $self = shift;
my $request = shift;