Commit 4fe52ecd authored by IKEDA Soji's avatar IKEDA Soji
Browse files

New request handler close_list to be integrated to Sympa::Request framework.

- WWSympa: do_close_list() and do_purge_list().
- sympa.pl --close_list and --purge_list.
- SympaSOAP: closeList().
parent f62b4ce3
......@@ -263,7 +263,6 @@ our %comm = (
'search_list' => 'do_search_list',
'search_list_request' => 'do_search_list_request',
'show_cert' => 'do_show_cert',
'close_list_request' => 'do_close_list_request',
'close_list' => 'do_close_list',
'purge_list' => 'do_purge_list',
'restore_list' => 'do_restore_list',
......@@ -530,7 +529,6 @@ our %required_args = (
'blacklist' => ['param.list'],
'move_user' => ['param.user.email', 'current_email|old_email', 'email|new_email'],
'close_list' => ['param.user.email', 'param.list'],
'close_list_request' => ['param.user.email', 'param.list'],
'compose_mail' => ['param.user.email', 'param.list'],
'copy_template' => ['webormail'],
## other required parameters are checked in the subroutine
......@@ -663,7 +661,6 @@ our %required_privileges = (
'auth_del' => ['owner', 'editor'],
'blacklist' => ['owner', 'editor'],
'close_list' => ['privileged_owner'],
'close_list_request' => ['privileged_owner'],
'copy_template' => ['listmaster'],
'd_install_shared' => ['editor', 'owner'],
'd_reject_shared' => ['editor', 'owner'],
......@@ -751,7 +748,6 @@ my %action_type = (
'viewbounce' => 'admin',
'resetbounce' => 'admin',
'scenario_test' => 'admin',
'close_list_request' => 'admin',
'close_list' => 'admin',
'restore_list' => 'admin',
'd_admin' => 'admin',
......@@ -9388,7 +9384,6 @@ sub do_get_pending_lists {
 
# get closed lists
sub do_get_closed_lists {
wwslog('info', '');
 
## Checking families and other virtual hosts.
......@@ -10984,18 +10979,7 @@ sub _do_edit_list_request {
#sub _restrict_values;
 
## NOT USED anymore (expect chinese)
sub do_close_list_request {
wwslog('info', '');
if ($list->{'admin'}{'status'} eq 'closed') {
Sympa::Report::reject_report_web('user', 'already_closed', {},
$param->{'action'}, $list);
wwslog('info', 'Already closed');
return undef;
}
return 1;
}
#sub do_close_list_request;
 
# in order to rename a list you must be list owner and you must be allowed to
# create new list
......@@ -11143,15 +11127,55 @@ sub do_move_list {
sub do_purge_list {
wwslog('info', '');
 
my @lists = split /\0/, $in{'selected_lists'};
my @lists = grep {$_} map {Sympa::List->new($_, $robot)}
grep {$_} split /\0/, $in{'selected_lists'};
return 'get_closed_lists' unless @lists;
 
foreach my $l (@lists) {
my $list = Sympa::List->new($l, $robot);
next unless (defined $list);
$list->purge($param->{'user'}{'email'});
$param->{'selected_lists'} = [map {$_->{'name'}} @lists];
# Action confirmed?
my $next_action = $session->confirm_action(
'purge_list', $in{'response_action'},
arg => join(',', @$param->{'selected_lists'}),
previous_action => 'get_closed_lists',
);
return $next_action unless $next_action eq '1';
my $spindle = Sympa::Spindle::ProcessRequest->new(
context => $robot,
action => 'close_list',
current_list => [@lists],
mode => 'purge',
sender => $param->{'user'}{'email'},
( $param->{'user'}{'email'}
? (md5_check => 1)
: ()
),
scenario_context => {
sender => $param->{'user'}{'email'},
remote_host => $param->{'remote_host'},
remote_addr => $param->{'remote_addr'},
},
);
unless ($spindle and $spindle->spin) {
wwslog('err', 'Cannot purge lists');
return 'get_closed_lists';
}
foreach my $report (@{$spindle->{stash} || []}) {
if ($report->[1] eq 'notice') {
Sympa::Report::notice_report_web(@{$report}[2, 3],
$param->{'action'});
} else {
Sympa::Report::reject_report_web(@{$report}[1 .. 3],
$param->{action});
}
}
unless (@{$spindle->{stash} || []}) {
Sympa::Report::notice_report_web('performed', {}, $param->{'action'});
}
 
Sympa::Report::notice_report_web('performed', {}, $param->{'action'});
web_db_log(
{ 'parameters' => $in{'selected_lists'},
'status' => 'success'
......@@ -11164,29 +11188,6 @@ sub do_purge_list {
sub do_close_list {
wwslog('info', '(%s)', $list->{'name'});
 
if ($list->{'admin'}{'status'} eq 'closed') {
Sympa::Report::reject_report_web('user', 'already_closed', {},
$param->{'action'}, $list);
wwslog('info', 'Already closed');
web_db_log(
{ 'status' => 'error',
'error_type' => 'already_closed'
}
);
return undef;
} elsif ($list->is_included) {
Sympa::Report::reject_report_web('user', 'cannot_close_list',
{reason => 'included'},
$param->{'action'}, $list);
wwslog('info', 'Cannot close list %s: Included by other list', $list);
web_db_log(
{ 'status' => 'error',
'error_type' => 'cannot_close_list'
}
);
return 'admin';
}
# Action confirmed?
my $next_action = $session->confirm_action(
$in{'action'}, $in{'response_action'},
......@@ -11195,36 +11196,46 @@ sub do_close_list {
);
return $next_action unless $next_action eq '1';
 
if ($list->{'admin'}{'status'} eq 'pending') {
wwslog('info', 'Closing a pending list makes it purged');
$list->purge($param->{'user'}{'email'});
Sympa::Report::notice_report_web('list_purged', {},
$param->{'action'});
web_db_log({'status' => 'success'});
my $mode = ($list->{'admin'}{'status'} eq 'pending') ? 'purge' : 'close';
my $spindle = Sympa::Spindle::ProcessRequest->new(
context => $robot,
action => 'close_list',
current_list => $list,
mode => $mode,
sender => $param->{'user'}{'email'},
( $param->{'user'}{'email'}
? (md5_check => 1)
: ()
),
 
web_db_stat_log();
scenario_context => {
sender => $param->{'user'}{'email'},
remote_host => $param->{'remote_host'},
remote_addr => $param->{'remote_addr'},
},
);
unless ($spindle and $spindle->spin) {
wwslog('err', 'Cannot close list %s', $list);
return 'admin';
}
 
return 'home';
} else {
unless ($list->close_list($param->{'user'}{'email'})) {
Sympa::Report::reject_report_web('intern', 'cannot_close_list',
{}, $param->{'action'}, $list, $param->{'user'}{'email'},
$robot);
wwslog('err', 'Cannot close list %s', $list);
web_db_log(
{ 'status' => 'error',
'error_type' => 'unknown'
}
);
foreach my $report (@{$spindle->{stash} || []}) {
if ($report->[1] eq 'notice') {
Sympa::Report::notice_report_web(@{$report}[2, 3],
$param->{'action'});
} else {
Sympa::Report::reject_report_web(@{$report}[1 .. 3],
$param->{action});
}
Sympa::Report::notice_report_web('list_closed', {},
$param->{'action'});
web_db_log({'status' => 'success'});
}
unless (@{$spindle->{stash} || []}) {
Sympa::Report::notice_report_web('performed', {}, $param->{'action'});
} elsif (not $spindle->success) {
return 'admin';
}
 
web_db_log({'status' => 'success'});
return ($mode eq 'purge') ? 'home' : 'admin';
}
 
sub do_restore_list {
......
......@@ -82,6 +82,7 @@ nobase_modules_DATA = \
Sympa/Request/Handler.pm \
Sympa/Request/Handler/add.pm \
Sympa/Request/Handler/auth.pm \
Sympa/Request/Handler/close_list.pm \
Sympa/Request/Handler/confirm.pm \
Sympa/Request/Handler/create_automatic_list.pm \
Sympa/Request/Handler/create_list.pm \
......
......@@ -725,9 +725,15 @@ sub close_family {
next;
}
unless (
$list->set_status_family_closed('close_list', $self->{'name'})) {
push(@impossible_close, $list->{'name'});
my $spindle = Sympa::Spindle::ProcessRequest->new(
context => $self->{'robot'},
action => 'close_list',
current_list => $list,
sender => Sympa::get_address($self, 'listmaster'),
scenario_context => {skip => 1},
);
unless ($spindle and $spindle->spin and $spindle->success) {
push @impossible_close, $list->{'name'};
next;
}
push(@close_ok, $list->{'name'});
......@@ -1025,15 +1031,16 @@ sub instantiate {
#}
}
if ($options{close_unknown} or $answer eq 'y') {
unless (
$list->set_status_family_closed(
'close_list', $self->{'name'}
)
) {
push(
@{$self->{'family_closed'}{'impossible'}},
$list->{'name'}
);
my $spindle = Sympa::Spindle::ProcessRequest->new(
context => $self->{'robot'},
action => 'close_list',
current_list => $list,
sender => Sympa::get_address($self, 'listmaster'),
scenario_context => {skip => 1},
);
unless ($spindle and $spindle->spin and $spindle->success) {
push @{$self->{'family_closed'}{'impossible'}},
$list->{'name'};
}
push(@{$self->{'family_closed'}{'ok'}}, $list->{'name'});
......
......@@ -455,28 +455,16 @@ sub set_status_error_config {
}
}
## set the list in status family_closed and send a notify to owners
sub set_status_family_closed {
$log->syslog('debug2', '(%s, %s, %s)', @_);
my $self = shift;
my $message = shift; # 'close_list', 'purge_list': Currently unused.
my @param = @_; # No longer used.
unless ($self->{'admin'}{'status'} eq 'family_closed') {
my $updater = Sympa::get_address($self->{'domain'}, 'listmaster');
unless ($self->close_list($updater, 'family_closed')) {
$log->syslog('err',
'Impossible to set the list %s in status family_closed');
return undef;
}
$log->syslog('info', 'The list "%s" is set in status family_closed',
$self->{'name'});
$self->send_notify_to_owner('list_closed_family', {});
}
return 1;
# Destroy multiton instance. FIXME
sub destroy_multiton {
my $self = shift;
delete $list_of_lists{$self->{'domain'}}{$self->{'name'}};
}
## set the list in status family_closed and send a notify to owners
# Deprecated. Use Sympa::Request::Handler::close_list handler.
#sub set_status_family_closed;
# Saves the statistics data to disk.
# Deprecated. Use Sympa::List::update_stats().
#sub savestats;
......@@ -9101,141 +9089,12 @@ sub remove_task {
return 1;
}
## Close the list (remove from DB, remove aliases, change status to 'closed'
## or 'family_closed')
sub close_list {
my ($self, $email, $status) = @_;
return undef
unless ($self
&& ($list_of_lists{$self->{'domain'}}{$self->{'name'}}));
# If list is included by another list, then it cannot be removed.
if ($self->is_included) {
$log->syslog('err',
'List %s is included by other list: cannot close it', $self);
return undef;
}
## Dump subscribers, unless list is already closed
unless ($self->{'admin'}{'status'} eq 'closed') {
$self->_save_list_members_file(
"$self->{'dir'}/subscribers.closed.dump");
}
## Delete users
my @users;
for (
my $user = $self->get_first_list_member();
$user;
$user = $self->get_next_list_member()
) {
push @users, $user->{'email'};
}
$self->delete_list_member('users' => \@users);
## Remove entries from admin_table
foreach my $role (qw(editor owner)) {
$self->delete_list_admin($role, $self->get_admins_email($role));
}
## Change status & save config
$self->{'admin'}{'status'} = 'closed';
if (defined $status) {
foreach my $s ('family_closed', 'closed') {
if ($status eq $s) {
$self->{'admin'}{'status'} = $status;
last;
}
}
}
$self->{'admin'}{'defaults'}{'status'} = 0;
$self->save_config($email);
$self->remove_aliases();
#log in stat_table to make staistics
$log->add_stat(
'robot' => $self->{'domain'},
'list' => $self->{'name'},
'operation' => 'close_list',
'parameter' => '',
'mail' => $email,
);
return 1;
}
# Deprecated. Use Sympa::Request::Handler::close_list handler.
#sub close_list;
## Remove the list
sub purge {
my ($self, $email) = @_;
return undef
unless ($self
&& ($list_of_lists{$self->{'domain'}}{$self->{'name'}}));
## Remove tasks for this list
Sympa::Task::list_tasks($Conf::Conf{'queuetask'});
foreach my $task (Sympa::Task::get_tasks_by_list($self->get_id)) {
unlink $task->{'filepath'};
}
## Close the list first, just in case...
$self->close_list();
if ($self->{'name'}) {
#FIXME: Lock directories to remove them safely.
my $error;
File::Path::remove_tree($self->get_archive_dir, {error => \$error});
File::Path::remove_tree($self->get_digest_spool_dir,
{error => \$error});
File::Path::remove_tree($self->get_bounce_dir, {error => \$error});
}
## Clean list table if needed
#if ($Conf::Conf{'db_list_cache'} eq 'on') {
my $sdm = Sympa::DatabaseManager->instance;
unless (
$sdm
and $sdm->do_prepared_query(
q{DELETE FROM list_table
WHERE name_list = ? AND robot_list = ?},
$self->{'name'}, $self->{'domain'}
)
) {
$log->syslog('err', 'Cannot remove list %s from table', $self);
}
#}
unless (
$sdm
and $sdm->do_prepared_query(
q{DELETE FROM inclusion_table
WHERE target_inclusion = ?},
$self->get_id
)
) {
$log->syslog('err', 'Cannot remove list %s from table', $self);
}
## Clean memory cache
delete $list_of_lists{$self->{'domain'}}{$self->{'name'}};
Sympa::Tools::File::remove_dir($self->{'dir'});
#log ind stat table to make statistics
$log->add_stat(
'robot' => $self->{'domain'},
'list' => $self->{'name'},
'operation' => 'purge_list',
'parameter' => '',
'mail' => $email
);
return 1;
}
# Deprecated. Use Sympa::Request::Handler::close_list handler.
#sub purge;
## Remove list aliases
sub remove_aliases {
......
......@@ -233,7 +233,8 @@ sub get_id {
}
} grep {
defined $self->{$_}
} qw(action context arc email reception visibility request error);
} qw(action context current_list listname arc mode email
reception visibility request error);
}
1;
......
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright 2017 The Sympa Community. See the AUTHORS.md file at the top-level
# directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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::close_list;
use strict;
use warnings;
use File::Path qw();
use Sympa;
use Sympa::Admin;
use Sympa::DatabaseManager;
use Sympa::Log;
use Sympa::Task;
use Sympa::Tools::File;
use base qw(Sympa::Request::Handler);
my $log = Sympa::Log->instance;
use constant _action_scenario => undef; # Only privileged owners allowed.
# Old names: Sympa::List::close_list(), Sympa::List::purge() and
# Sympa::List::set_status_family_closed().
sub _twist {
my $self = shift;
my $request = shift;
my $list = $request->{current_list};
my $sender = $request->{sender};
my $mode = $request->{mode} || 'close';
# If list is included by another list, then it cannot be removed.
if ($list->is_included) {
$log->syslog('err',
'List %s is included by other list: cannot close it', $list);
$self->add_stash($request, 'user', 'cannot_close_list',
{reason => 'included', listname => $list->{'name'}});
return undef;
}
if ($mode eq 'close') {
if (grep { $list->{'admin'}{'status'} eq $_ }
qw(closed family_closed)) {
$log->syslog('err',
'List %s is already closed: cannot close it again', $list);
$self->add_stash('user', 'already_closed',
{listname => $list->{'name'}});
return undef;
}
_close($self, $request);
$log->syslog(
'info', 'The list %s is set in status %s',
$list, $list->{'admin'}{'status'}
);
$self->add_stash($request, 'notice', 'list_closed',
{listname => $list->{'name'}});
#FIXME: No owners!
$list->send_notify_to_owner('list_closed_family', {})
if $list->{'admin'}{'family_name'};
$log->add_stat(
'robot' => $list->{'domain'},
'list' => $list->{'name'},
'operation' => 'close_list',
'parameter' => '',
'mail' => $sender,
);
} elsif ($mode eq 'purge') {
unless (grep { $list->{'admin'}{'status'} eq $_ }
qw(closed family_closed)) {
_close($self, $request);
}
_purge($self, $request);
$log->syslog('info', 'The list %s is purged', $list);
$self->add_stash($request, 'notice', 'list_purged',
{listname => $list->{'name'}});
$log->add_stat(
'robot' => $list->{'domain'},
'list' => $list->{'name'},
'operation' => 'purge_list',
'parameter' => '',
'mail' => $sender
);
} else {
die 'bug in logic. Ask developer';
}
return 1;
}
sub _close {
my $self = shift;
my $request = shift;
my $list = $request->{current_list};
my $sender = $request->{sender};
Sympa::Admin::remove_aliases($list);
# Dump subscribers.
$list->_save_list_members_file(
$list->{'dir'} . '/subscribers.closed.dump');
## Delete users
my @users;
for (
my $user = $list->get_first_list_member();
$user;
$user = $list->get_next_list_member()
) {
push @users, $user->{'email'};
}
$list->delete_list_member('users' => \@users);
# Remove entries from admin_table.
foreach my $role (qw(editor owner)) {
$list->delete_list_admin($role, $list->get_admins_email($role));
}
# Change status & save config.
$list->{'admin'}{'status'} =
$list->{'admin'}{'family_name'} ? 'family_closed' : 'closed';
$list->{'admin'}{'defaults'}{'status'} = 0; #FIXME
$list->save_config($sender || Sympa::get_address($list, 'listmaster'));
return 1;
}
# Old name: (part of) Sympa::List::purge().
sub _purge {
my $self = shift;
my $request = shift;
my $list = $request->{current_list};
my $sender = $request->{sender};
# Remove tasks for this list.
Sympa::Task::list_tasks($Conf::Conf{'queuetask'});
foreach my $task (Sympa::Task::get_tasks_by_list($list->get_id)) {
unlink $task->{'filepath'};
}