Commit 2dddb4bd authored by IKEDA Soji's avatar IKEDA Soji
Browse files

[-feature] WWSympa: New action "edit" to edit owner/editor.

[-feature] "owner" and "editor" in list profile (create list template) are written in dump files when a list is created.

ToDo: edit.tt2 should refer to edit_list.conf.
parent bce90587
<!-- edit.tt2 -->
<h2>
[% IF role == 'owner' ~%]
[%|loc%]Owner[%END%]
[%~ ELSIF role == 'editor' ~%]
[%|loc%]Moderator[%END%]
[%~ ELSE ~%]
[% RETURN %]
[%~ END %]
</h2>
<form action="[% path_cgi %]" method="post">
<fieldset>
[% SET pV = config_values.${role}.0 ~%]
<input type="hidden" name="previous_action" value="[% previous_action %]" />
<input type="hidden" name="list" value="[% list %]" />
<input type="hidden" name="role" value="[% role %]" />
<input type="hidden" name="email" value="[% pV.email %]" />
<div class="row">
<div class="columns">
<label for="email">[%|loc%]Email:[%END%] </label>
[% pV.email %]
</div>
<div class="columns">
<label for="gecos">[%|loc%]Name:[%END%] </label>
<input type="text" name="single_param.[% role %].0.gecos" id="gecos"
value="[% pV.gecos %]" size="25" />
</div>
[% IF is_privileged_owner ~%]
<div class="columns">
<label for="info">[%|loc%]private information[%END%] </label>
<input type="text" name="single_param.[% role %].0.info" id="info"
value="[% pV.info %]" size="30" />
</div>
[%~ END %]
[% IF role == 'owner' ~%]
<div class="columns">
<label for="profile">[%|loc%]profile[%END%] </label>
[% IF is_listmaster ~%]
<select name="single_param.[% role %].0.profile" id="profile">
[% FOREACH r = ['normal', 'privileged'] ~%]
<option value="[% r %]"
[%~ IF r == pV.profile %] selected="selected"[% END ~%]
>
[%~ r | optdesc ~%]
</option>
[% END %]
</select>
[%~ ELSE ~%]
[% pV.profile | optdesc %]
[%~ END %]
</div>
[%~ END %]
<div class="columns">
<label for="reception">[%|loc%]Receiving:[%END%] </label>
<select name="single_param.[% role %].0.reception" id="reception">
[% FOREACH r = ['mail', 'nomail'] ~%]
<option value="[% r %]"
[%~ IF r == pV.reception %] selected="selected"[% END ~%]
>
[%~ r | optdesc ~%]
</option>
[% END %]
</select>
</div>
<div class="columns">
<label for="visibility">[%|loc%]Visibility:[%END%] </label>
<select id="visibility" name="single_param.[% role %].0.visibility">
[% FOREACH r = ['noconceal', 'conceal'] ~%]
<option value="[% r %]"
[%~ IF r == pV.visibility %] selected="selected"[% END ~%]
>
[%~ r | optdesc ~%]
</option>
[% END %]
</select>
</div>
<div class="columns">
<label>[%|loc%]Delegated since:[%END%] </label>
[% pV.date | optdesc('unixtime') %]
</div>
<div class="columns">
<label>[%|loc%]Last update:[%END%] </label>
[% pV.update_date | optdesc('unixtime') %]
</div>
[% IF is_privileged_owner ~%]
<input type="hidden" name="submit" value="submit" />
<div class="columns">
<input class="MainMenuLinks" type="submit" name="action_edit"
value="[%|loc%]Update[%END%]" />
</div>
[%~ END %]
</div>
</fieldset>
</form>
<!-- end edit.tt2 -->
......@@ -56,7 +56,12 @@
<div class="item_content">
<a class="item_title" href="[% 'admin' | url_rel([list]) %]"><i class="fa fa-wrench fa-3x pull-left fa-border"></i> [%|loc%]List Configuration[%END%]</a>
<ul class="fa-ul">
<li><i class="fa-li fa fa-arrow-right"></i><a href="[% 'edit_list_request' | url_rel([list,'description']) %]">[%|loc%]Modify owners or moderators (editors)[%END%]</a></li>
<li>
<i class="fa-li fa fa-arrow-right"></i>
<a href="[% 'review' | url_rel([list,'owner']) %]">
[%|loc%]Modify owners or moderators (editors)[%END%]
</a>
</li>
<li><i class="fa-li fa fa-arrow-right"></i><a href="[% 'edit_list_request' | url_rel([list,'description']) %]">[%|loc%]Modify list subject and visibility[%END%]</a></li>
<li><i class="fa-li fa fa-arrow-right"></i><a href="[% 'edit_list_request' | url_rel([list,'sending']) %]">[%|loc%]Change who can post to this list[%END%]</a></li>
<li><i class="fa-li fa fa-arrow-right"></i><a href="[% 'edit_list_request' | url_rel([list,'command']) %]">[%|loc%]Change who can (un)subscribe and view list information[%END%]</a></li>
......
......@@ -43,7 +43,10 @@
[% IF is_priv %]
<span>
<a href="[% 'edit_list_request' | url_rel([list,'description'],{},'owner') %]"><i class="fa fa-pencil-square fa-lg" title="[%|loc%](Edit)[%END%]"></i></a>
<a href="[% 'review' | url_rel([list,'owner']) %]">
<i class="fa fa-pencil-square fa-lg" title="[%|loc%](Edit)[%END%]">
</i>
</a>
</span>
[% END %]
</span>
......@@ -78,7 +81,10 @@
[% IF is_priv %]
<span>
<a href="[% 'edit_list_request' | url_rel([list,'description'],{},'editor') %]"><i class="fa fa-pencil-square fa-lg" title="[%|loc%](Edit)[%END%]"></i></a>
<a href="[% 'review' | url_rel([list,'editor']) %]">
<i class="fa fa-pencil-square fa-lg" title="[%|loc%](Edit)[%END%]">
</i>
</a>
</span>
[% END %]
</span>
......
......@@ -4,9 +4,11 @@
[% PROCESS ReviewMembers ~%]
[%~ ELSIF page == 'owner' ~%]
[% PROCESS ReviewUsers
role = page
users = owners %]
[%~ ELSIF page == 'editor' ~%]
[% PROCESS ReviewUsers
role = page
users = editors %]
[%~ END %]
......@@ -218,11 +220,12 @@
[%~ END #ReviewMembers %]
[%~ BLOCK ReviewUsers # (users) ~%]
[%~ BLOCK ReviewUsers # (role,users) ~%]
<h2>
[% IF page == 'owner' ~%]
[% IF role == 'owner' ~%]
[%|loc%]Owners[%END%]
[%~ ELSIF page == 'editor' ~%]
[%~ ELSIF role == 'editor' ~%]
[%|loc%]Moderators[%END%]
[%~ END %]
</h2>
......@@ -231,7 +234,7 @@
<fieldset role="table">
<input type="hidden" name="list" value="[% list %]" />
<input type="hidden" name="action" value="review" />
<input type="hidden" name="page" value="[% page %]" />
<input type="hidden" name="page" value="[% role %]" />
<div class="row" role="row">
<div class="small-10 medium-11 columns">
......@@ -278,16 +281,22 @@
<div class="small-10 medium-11 columns" id="item.user.[% idx %]">
<div class="small-6 medium-4 columns" role="cell">
<span class="show-for-medium-up">
[%~ IF page == 'owner' && u.profile == 'privileged' ~%]
[%~ IF role == 'owner' && u.profile == 'privileged' ~%]
<i class="fa fa-fw fa-star"
title="[%|loc%]Privileged owner[%END%]"></i>
[%~ ELSIF page == 'owner' ~%]
[%~ ELSIF role == 'owner' ~%]
<i class="fa fa-fw" title="[%|loc%]Owner[%END%]"></i>
[%~ ELSIF page == 'editor' ~%]
[%~ ELSIF role == 'editor' ~%]
<i class="fa fa-fw" title="[%|loc%]Moderator[%END%]"></i>
[%~ END %]
</span>
[% u.email %]
[% IF is_privileged_owner ~%]
<a href="[% 'ajax/edit' | url_rel([list,role],{email=>u.email,previous_action=>action}) %]"
data-reveal-id="edit" data-reveal-ajax="true"
class="MainMenuLinks">[% u.email %]</a>
[%~ ELSE ~%]
[% u.email %]
[%~ END %]
</div>
<div class="small-6 medium-4 columns" role="cell">
......@@ -333,26 +342,26 @@
[%~ ELSE ~%]
<p
class="small-12 medium-8 medium-centered columns alert-box info text-center">
[% IF page == 'owner' ~%]
[% IF role == 'owner' ~%]
[%|loc%]List has no owners[%END%]
[%~ ELSIF page == 'editor' ~%]
[%~ ELSIF role == 'editor' ~%]
[%|loc%]List has no moderators[%END%]
[%~ END %]
</p>
[%~ END %]
<h3>
[% IF page == 'owner' ~%]
[%|loc%]Add owners[%END%]
[%~ ELSIF page == 'editor' ~%]
[%|loc%]Add momderators[%END%]
[%~ END %]
</h3>
[% IF is_privileged_owner ~%]
<h3>
[% IF role == 'owner' ~%]
[%|loc%]Add owners[%END%]
[%~ ELSIF role == 'editor' ~%]
[%|loc%]Add momderators[%END%]
[%~ END %]
</h3>
<div class="row" id="item.user.0.new" role="row">
<div class="small-10 medium-11 columns">
[% IF page == 'owner' ~%]
[% IF role == 'owner' ~%]
<div class="columns show-for-medium-up" role="cell">
<input type="checkbox"
name="single_param.user.0.profile" id="param.user.0.profile"
......@@ -401,6 +410,13 @@
</fieldset>
</form>
[%# AJAX modal dialog ~%]
<div id="edit" class="reveal-modal medium" data-reveal
aria-labelledby="[%|loc%]View user[%END%]" aria-hidden="true"
role="dialog">
[%# empty div that will display a content by AJAX. ~%]
</div>
[%~ END#ReviewUsers ~%]
<!-- end review.tt2 -->
......@@ -51,6 +51,21 @@
</pre>
</div>
<h2>[%|loc%]Users[%END%]</h2>
<ul>
<li>
<a href="[% 'review' | url_rel([list,'owner']) %]">
[%|loc%]Owners[%END%]
</a>
</li>
<li>
<a href="[% 'review' | url_rel([list,'editor']) %]">
[%|loc%]Moderators[%END%]
</a>
</li>
</ul>
<div class="block">
<h2>[%|loc%]Configuration file[%END%]</h2>
[% IF is_listmaster ~%]
......
......@@ -249,6 +249,7 @@ our %comm = (
'edit_config' => 'do_edit_config',
#XXX'submit_list' => 'do_submit_list',
'editsubscriber' => 'do_editsubscriber',
'edit' => 'do_edit',
'viewbounce' => 'do_viewbounce',
'redirect' => 'do_redirect',
'rename_list_request' => 'do_rename_list_request',
......@@ -403,6 +404,7 @@ our %action_args = (
# ['list', 'email', 'previous_action', 'custom_attribute'],
#'editsubscriber' => ['list', 'email', 'previous_action'],
'editsubscriber' => ['list'],
'edit' => ['list', 'role'],
#'viewbounce' => ['list', 'email', '@file'],
'viewbounce' => ['list', 'dir', '@file'],
#'resetbounce' => ['list', 'email'],
......@@ -558,6 +560,7 @@ our %required_args = (
'distribute' => ['param.list', 'param.user.email', 'id|idspam'],
'add_frommod' => ['param.list', 'param.user.email', 'id'],
'dump_scenario' => ['param.list', 'pname'],
'edit' => ['param.list', 'param.user.email', 'role', 'email'],
'edit_list' => ['param.user.email', 'param.list'],
'edit_list_request' => ['param.user.email', 'param.list'],
'edit_template' => ['webormail'],
......@@ -666,6 +669,7 @@ our %required_privileges = (
'distribute' => ['editor', 'owner', 'listmaster'],
'add_frommod' => ['editor', 'owner'],
'dump_scenario' => ['listmaster'],
'edit' => ['editor', 'owner', 'listmaster'],
'edit_list' => ['owner'],
'edit_list_request' => ['owner'],
'edit_template' => ['listmaster'],
......@@ -741,6 +745,7 @@ my %action_type = (
'savefile' => 'admin',
'rebuildallarc' => 'admin', #FIXME: serveradmin?
'reviewbouncing' => 'admin',
'edit' => 'admin',
'edit_list_request' => 'admin',
'edit_list' => 'admin',
'editsubscriber' => 'admin',
......@@ -751,8 +756,8 @@ my %action_type = (
'd_admin' => 'admin',
'd_reject_shared' => 'admin',
'd_install_shared' => 'admin',
'export_member' => 'admin',
'dump_scenario' => 'admin',
'export_member' => 'admin',
'open_list' => 'admin',
'remind' => 'admin',
#'subindex' => 'admin',
......@@ -961,6 +966,9 @@ our %in_regexp = (
 
## Authentication/moderation key
'authkey' => '\w+',
# Role
'role' => 'member|editor|owner',
);
 
## Regexp applied on incoming parameters (%in)
......@@ -4949,6 +4957,83 @@ sub _review_member {
return 1;
}
 
sub do_edit {
wwslog('info', '(%s, %s)', $in{'role'}, $in{'email'});
my $role = $in{'role'};
my $email = $in{'email'};
$param->{'role'} = $role;
$param->{'page'} = $role; # For review action
my @keys = qw(gecos profile info reception visibility);
#FIXME: Provide config schema including privileges by Family.
my $schema = {};
my ($role_p, $priv_p) = $list->may_edit($role, $param->{'user'}{'email'});
foreach my $key (@keys) {
my ($role, $priv) =
$list->may_edit("$role.$key", $param->{'user'}{'email'});
my $pitem = $schema->{$key} = {};
$priv = $priv_p
if not $priv
or ($priv_p and $priv_p lt $priv);
$pitem->{privilege} = $priv
if not $pitem->{privilege}
or ($priv and $priv lt $pitem->{privilege});
$pitem->{privilege} ||= 'hidden'; # Implicit default
}
# Initial access. show current value.
unless ($in{'submit'}) {
$param->{'config_schema'} = $schema;
my ($user) =
grep { $_ and $_->{email} eq $email and $_->{role} eq $role }
@{$list->get_current_admins || []};
$param->{'config_values'} = {$role => [$user]} if $user;
$param->{'previous_action'} = $in{'previous_action'} || 'review';
return 1;
} else {
# Start parsing the data sent by the edition form.
my $new_config = _deserialize_changes();
my $new = $new_config->{$role}->[0] || {} if $new_config;
my $values = {};
foreach my $key (@keys) {
next unless $schema->{$key}{privilege}
and $schema->{$key}{privilege} eq 'write';
if ($key eq 'gecos') {
$values->{gecos} = (defined $new->{gecos}) ? $new->{gecos} : ''
if exists $new->{gecos};
} elsif ($key eq 'reception') {
$values->{reception} = $new->{reception}
if $new->{reception}
and grep {$new->{reception} eq $_} qw(mail nomail);
} elsif ($key eq 'visibility') {
$values->{visibility} = $new->{visibility}
if $new->{visibility}
and grep {$new->{visibility} eq $_}
qw(conceal noconceal);
} elsif ($key eq 'profile') {
$values->{profile} = $new->{profile}
if $new->{profile}
and grep {$new->{profile} eq $_} qw(normal privileged);
} elsif ($key eq 'info') {
$values->{info} = (defined $new->{info}) ? $new->{info} : ''
if exists $new->{info};
}
}
$list->update_list_admin($email, $role, $values)
if $values and %$values;
$in{'page'} = $role; # For review.
return $in{'previous_action'} || 'review';
}
}
## Show the table of exclude
sub do_show_exclude {
wwslog('info', '');
......@@ -10804,29 +10889,6 @@ sub do_edit_list_request {
 
return 1 unless $in{'group'};
 
# Sync owner/editor in list config with database.
# FIXME: TENTATIVE FIX.
my @static_admins =
grep {$_ and $_->{'subscribed'}} @{$list->_get_admins || []};
my @subparams;
# Current static owners.
my $static_owner =
[grep { $_->{'role'} and $_->{'role'} eq 'owner' } @static_admins];
@subparams = qw(email gecos info profile reception visibility);
foreach my $u (@$static_owner) {
$u = {map { $_ => $u->{$_} } @subparams};
}
$list->{'admin'}{'owner'} = $static_owner;
# Current static editors.
my $static_editor =
[grep { $_->{'role'} and $_->{'role'} eq 'editor' } @static_admins];
@subparams = qw(email gecos info reception visibility);
foreach my $u (@$static_editor) {
$u = {map { $_ => $u->{$_} } @subparams};
}
$list->{'admin'}{'editor'} = $static_editor;
# FIXME: END OF TENTATIVE FIX.
my $config = Sympa::List::Config->new($list, config => $list->{'admin'});
my $schema = $config->get_schema($param->{'user'}{'email'});
 
......
......@@ -177,7 +177,23 @@ sub _twist {
$self->add_stash($request, 'intern');
return undef;
}
print $lock_fh $config;
# Write config.
# - Write out initial permanent owners/editors in <role>.dump files.
# - Write reminder to config file.
$config =~ s/(\A|\n)[\t ]+(?=\n)/$1/g; # normalize empty lines
open my $ifh, '<', \$config; # open "in memory" file
my @config = do { local $RS = ''; <$ifh> };
close $ifh;
foreach my $role (qw(owner editor)) {
my $file = $list_dir . '/' . $role . '.dump';
if (!-e $file and open my $ofh, '>', $file) {
my $admins = join '', grep {/\A\s*$role\b/} @config;
print $ofh $admins;
close $ofh;
}
}
print $lock_fh join '', grep { !/\A\s*(owner|editor)\b/ } @config;
## Unlock config file
$lock_fh->close;
......@@ -235,12 +251,18 @@ sub _twist {
## Create list object
my $list;
unless ($list = Sympa::List->new($listname, $robot_id)) {
unless ($list =
Sympa::List->new($listname, $robot_id, {skip_sync_admin => 1})) {
$log->syslog('err', 'Unable to create list %s', $listname);
$self->add_stash($request, 'intern');
return undef;
}
# Store initial permanent list users.
$list->restore_users('member');
$list->restore_users('owner');
$list->restore_users('editor');
if ($listname ne $request->{listname}) {
$self->add_stash($request, 'notice', 'listname_lowercased');
}
......
......@@ -211,7 +211,22 @@ sub _twist {
return undef;
}
print $lock_fh $config;
# Write config.
# - Write out initial permanent owners/editors in <role>.dump files.
# - Write reminder to config file.
$config =~ s/(\A|\n)[\t ]+(?=\n)/$1/g; # normalize empty lines
open my $ifh, '<', \$config; # open "in memory" file
my @config = do { local $RS = ''; <$ifh> };
close $ifh;
foreach my $role (qw(owner editor)) {
my $file = $list_dir . '/' . $role . '.dump';
if (!-e $file and open my $ofh, '>', $file) {
my $admins = join '', grep {/\A\s*$role\b/} @config;
print $ofh $admins;
close $ofh;
}
}
print $lock_fh join '', grep { !/\A\s*(owner|editor)\b/ } @config;
## Unlock config file
$lock_fh->close;
......@@ -234,12 +249,18 @@ sub _twist {
# Create list object.
my $list;
unless ($list = Sympa::List->new($listname, $robot_id)) {
unless ($list =
Sympa::List->new($listname, $robot_id, {skip_sync_admin => 1})) {
$log->syslog('err', 'Unable to create list %s', $listname);
$self->add_stash($request, 'intern');
return undef;
}
# Store initial permanent list users.
$list->restore_users('member');
$list->restore_users('owner');
$list->restore_users('editor');
if ($listname ne $request->{listname}) {
$self->add_stash($request, 'notice', 'listname_lowercased');
}
......
......@@ -81,30 +81,15 @@ sub _twist {
return undef;
}
# Dump initial permanent owners/editors in config file.
if ($mode eq 'install') {
my ($fh, $fh_config);
foreach my $role (qw(owner editor)) {
my $file = $list->{'dir'} . '/' . $role . '.dump';
my $config = $list->{'dir'} . '/config';
if ( !-e $file
and open($fh, '>', $file)
and open($fh_config, '<', $config)) {
local $RS = ''; # read paragraph by each
my $admins = join '', grep {/\A\s*$role\b/} <$fh_config>;
print $fh $admins;
close $fh;
close $fh_config;
}
}
}
# Load permanent users.
$list->restore_users('member');
$list->restore_users('owner');
$list->restore_users('editor');
# Load initial transitional owners/editors from external data sources.
if ($mode eq 'install') {
if ($mode eq 'open') {
# Restore permanent/transitional list users dumped by close_list.
$list->restore_users('member');
$list->restore_users('owner');
$list->restore_users('editor');
} elsif ($mode eq 'install') {
# Since initial poermanent list users have been stored by create_list
# or create_automatic_list, add transitional owners/editors from
# external data sources.
$list->sync_include_admin;
}
......
......@@ -529,7 +529,8 @@ $(function() {
/* Add "Close" button to popup showing bounce. */
$(function() {
$('#mainviewbounce, #mainviewmod').on('opened.fndtn.reveal', function(){
$('#edit, #mainviewbounce, #mainviewmod')
.on('opened.fndtn.reveal', function(){
var closeButton =
$('<a class="close-reveal-modal" aria-label="' + sympa.closeText
+ '">&#215;</a>');
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment