Commit 9fc38317 authored by IKEDA Soji's avatar IKEDA Soji
Browse files

[-change] Database schema: inclusion_ext_* fields in subscriber_table and...

[-change] Database schema: inclusion_ext_* fields in subscriber_table and admin_table to give the last time of inclusion from external data sources.
"External" means that it is not include_sympa_list or not including list on local domain.
Note that if inclusion_ext_* field is updated, inclusion_* field must be updated at the same time.

Known bug:
  - If data source is a list included from the other external data source(s), it will be treated as non-external and move_user request on corresponding users will be allowed.
parent ae01bc36
......@@ -131,6 +131,12 @@ my %full_db_struct = (
'the last time when list user is synchronized with data source',
'order' => 12.6,
},
'inclusion_ext_subscriber' => {
'struct' => 'int(11)',
'doc' =>
'the last time when list user is synchronized with external data source',
'order' => 12.7,
},
'comment_subscriber' => {
'struct' => 'varchar(150)',
'doc' => 'free form name',
......@@ -933,6 +939,12 @@ my %full_db_struct = (
'the last time when list user is synchronized with data source',
'order' => 7.6,
},
'inclusion_ext_admin' => {
'struct' => 'int(11)',
'doc' =>
'the last time when list user is synchronized with external data source',
'order' => 7.7,
},
'reception_admin' => {
'struct' => 'varchar(20)',
'doc' =>
......
......@@ -3737,34 +3737,36 @@ sub update_list_admin {
## mapping between var and field names
my %map_field = (
reception => 'reception_admin',
visibility => 'visibility_admin',
date => 'date_epoch_admin',
update_date => 'update_epoch_admin',
inclusion => 'inclusion_admin',
gecos => 'comment_admin',
password => 'password_user',
email => 'user_admin',
subscribed => 'subscribed_admin',
info => 'info_admin',
profile => 'profile_admin',
role => 'role_admin'
reception => 'reception_admin',
visibility => 'visibility_admin',
date => 'date_epoch_admin',
update_date => 'update_epoch_admin',
inclusion => 'inclusion_admin',
inclusion_ext => 'inclusion_ext_admin',
gecos => 'comment_admin',
password => 'password_user',
email => 'user_admin',
subscribed => 'subscribed_admin',
info => 'info_admin',
profile => 'profile_admin',
role => 'role_admin'
);
## mapping between var and tables
my %map_table = (
reception => 'admin_table',
visibility => 'admin_table',
date => 'admin_table',
update_date => 'admin_table',
inclusion => 'admin_table',
gecos => 'admin_table',
password => 'user_table',
email => 'admin_table',
subscribed => 'admin_table',
info => 'admin_table',
profile => 'admin_table',
role => 'admin_table'
reception => 'admin_table',
visibility => 'admin_table',
date => 'admin_table',
update_date => 'admin_table',
inclusion => 'admin_table',
inclusion_ext => 'admin_table',
gecos => 'admin_table',
password => 'user_table',
email => 'admin_table',
subscribed => 'admin_table',
info => 'admin_table',
profile => 'admin_table',
role => 'admin_table'
);
#### ??
## additional DB fields
......@@ -4015,7 +4017,7 @@ sub add_list_member {
(user_subscriber, comment_subscriber,
list_subscriber, robot_subscriber,
date_epoch_subscriber, update_epoch_subscriber,
inclusion_subscriber,
inclusion_subscriber, inclusion_ext_subscriber,
reception_subscriber, topics_subscriber,
visibility_subscriber, subscribed_subscriber,
custom_attribute_subscriber,
......@@ -4023,11 +4025,11 @@ sub add_list_member {
suspend_start_date_subscriber,
suspend_end_date_subscriber,
number_messages_subscriber)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)},
$who, $new_user->{'gecos'},
$name, $self->{'domain'},
$new_user->{'date'}, $new_user->{'update_date'},
$new_user->{'inclusion'},
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)},
$who, $new_user->{'gecos'},
$name, $self->{'domain'},
$new_user->{'date'}, $new_user->{'update_date'},
$new_user->{'inclusion'}, $new_user->{'inclusion_ext'},
$new_user->{'reception'}, $new_user->{'topics'},
$new_user->{'visibility'}, $new_user->{'subscribed'},
$new_user->{'custom_attribute'},
......@@ -4496,7 +4498,7 @@ sub restore_users {
Sympa::Tools::Data::decode_custom_attribute($2);
($decoded and %$decoded) ? ($k => $decoded) : ();
} elsif (
/^\s*(date|update_date|inclusion|startdate|enddate|bounce_score|number_messages)\s+(\d+)\s*$/
/^\s*(date|update_date|inclusion|inclusion_ext|startdate|enddate|bounce_score|number_messages)\s+(\d+)\s*$/
or
/^\s*(reception)\s+(mail|digest|nomail|summary|notice|txt|html|urlize|not_me)\s*$/
or /^\s*(visibility)\s+(conceal|noconceal)\s*$/
......@@ -4530,7 +4532,8 @@ sub restore_users {
($1 => !!$2);
} elsif (/^\s*(email|gecos|info|id)\s+(.+)\s*$/
or /^\s*(profile)\s+(normal|privileged)\s*$/
or /^\s*(date|update_date|inclusion)\s+(\d+)\s*$/
or
/^\s*(date|update_date|inclusion|inclusion_ext)\s+(\d+)\s*$/
or /^\s*(reception)\s+(mail|nomail)\s*$/
or /^\s*(visibility)\s+(conceal|noconceal)\s*$/) {
($1 => $2);
......
......@@ -2840,6 +2840,13 @@ our %user_info = (
field_type => 'unixtime',
internal => 1,
},
inclusion_ext => {
order => 14.7,
gettext_id => 'last inclusion time from external data source',
format => '\d+',
field_type => 'unixtime',
internal => 1,
},
},
occurrence => '1-n'
},
......@@ -2932,6 +2939,13 @@ our %user_info = (
field_type => 'unixtime',
internal => 1,
},
inclusion_ext => {
order => 14.7,
gettext_id => 'last inclusion time from external data source',
format => '\d+',
field_type => 'unixtime',
internal => 1,
},
},
occurrence => '0-n'
},
......
......@@ -246,13 +246,23 @@ sub _twist {
unless (
$sdm->do_prepared_query(
qq{UPDATE ${t}_table
SET inclusion_$t = NULL
SET inclusion_$t = NULL, inclusion_ext_$t = NULL
WHERE subscribed_$t = 1 AND
inclusion_$t IS NOT NULL AND inclusion_$t < ? AND
list_$t = ? AND robot_$t = ?$r},
$last_start,
$list->{'name'}, $list->{'domain'}
)
and $sdm->do_prepared_query(
qq{UPDATE ${t}_table
SET inclusion_ext_$t = NULL
WHERE subscribed_$t = 1 AND
inclusion_ext_$t IS NOT NULL AND
inclusion_ext_$t < ? AND
list_$t = ? AND robot_$t = ?$r},
$last_start,
$list->{'name'}, $list->{'domain'}
)
) {
#FIXME: report error
}
......@@ -261,7 +271,7 @@ sub _twist {
_clean_inclusion_table($list, $role, $last_start);
}
# III. Update custom attributes.
# IV. Update custom attributes.
if ($role eq 'member') {
my $dss = _get_data_sources($list, 'custom_attribute');
......@@ -393,6 +403,8 @@ sub _sync_ds_user {
($role eq 'member')
? ('subscriber', '')
: ('admin', sprintf ' AND role_admin = %s', $sdm->quote($role));
my $is_external_ds = not(ref $ds eq 'Sympa::DataSource::List'
and [split /\@/, $ds->{listname}, 2]->[1] eq $list->{'domain'});
# 1. If role of the data source is 'member' and the user is excluded:
# Do nothing.
......@@ -401,28 +413,50 @@ sub _sync_ds_user {
# 2. If user has already been updated by the other data sources:
# Keep user.
return unless $sth = $sdm->do_prepared_query(
qq{SELECT COUNT(*)
FROM ${t}_table
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r AND
inclusion_$t IS NOT NULL AND ? <= inclusion_$t},
$email, $list->{'name'}, $list->{'domain'},
$sync_start
);
if ($is_external_ds) {
return unless $sth = $sdm->do_prepared_query(
qq{SELECT COUNT(*)
FROM ${t}_table
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r AND
inclusion_$t IS NOT NULL AND ? <= inclusion_$t AND
inclusion_ext_$t IS NOT NULL AND ? <= inclusion_ext_$t},
$email, $list->{'name'}, $list->{'domain'},
$sync_start, $sync_start
);
} else {
return unless $sth = $sdm->do_prepared_query(
qq{SELECT COUNT(*)
FROM ${t}_table
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r AND
inclusion_$t IS NOT NULL AND ? <= inclusion_$t},
$email, $list->{'name'}, $list->{'domain'},
$sync_start
);
}
my ($count) = $sth->fetchrow_array;
$sth->finish;
return (kept => 1) if $count;
# 3. If user (has not been updated by the other data sources and) exists:
# UPDATE inclusion.
return unless $sth = $sdm->do_prepared_query(
qq{UPDATE ${t}_table
SET inclusion_$t = ?
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r},
$time,
$email, $list->{'name'}, $list->{'domain'}
);
return (updated => 1) if $sth->rows;
if ($is_external_ds) {
return unless $sth = $sdm->do_prepared_query(
qq{UPDATE ${t}_table
SET inclusion_$t = ?, inclusion_ext_$t = ?
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r},
$time, $time,
$email, $list->{'name'}, $list->{'domain'}
);
} else {
return unless $sth = $sdm->do_prepared_query(
qq{UPDATE ${t}_table
SET inclusion_$t = ?
WHERE user_$t = ? AND list_$t = ? AND robot_$t = ?$r},
$time,
$email, $list->{'name'}, $list->{'domain'}
);
}
return (updated => 1) if $sth->rows; #FIXME: Duplicate counts
# 4. Otherwise, i.e. a new user:
# INSERT new user with:
......@@ -435,6 +469,7 @@ sub _sync_ds_user {
date => $time,
update_date => $time,
inclusion => $time,
($is_external_ds ? (inclusion_ext => $time) : ()),
};
my @defkeys = @{$ds->{_defkeys} || []};
my @defvals = @{$ds->{_defvals} || []};
......
......@@ -68,34 +68,32 @@ sub _twist {
{
my $user_entry = $list->get_list_member($current_email);
if ($user_entry and defined $user_entry->{'inclusion'}) {
# Check the type of data sources.
# If only include_sympa_list of local mailing lists, then no
# problem. Otherwise, notify list owner.
#FIXME: Currently include_sympa_list is not omitted.
if (defined $user_entry->{'inclusion'}) {
# Notify list owner.
$list->send_notify_to_owner(
'failed_to_change_included_member',
{ 'current_email' => $current_email,
'new_email' => $email,
'datasource' => '',
}
);
$self->add_stash(
$request, 'user',
'change_member_email_failed_included',
{email => $current_email, listname => $list->{'name'}}
);
$log->syslog(
'err',
'Could not change member email %s for list %s to %s because member is included',
$current_email,
$list,
$email
);
next;
}
# Check the type of data sources.
# If only include_sympa_list of local mailing lists, then no
# problem. Otherwise, notify list owner.
#FIXME: Consider the case source list is included from external
# data source.
if ($user_entry and defined $user_entry->{'inclusion_ext'}) {
$list->send_notify_to_owner(
'failed_to_change_included_member',
{ 'current_email' => $current_email,
'new_email' => $email,
'datasource' => '',
}
);
$self->add_stash(
$request, 'user',
'change_member_email_failed_included',
{email => $current_email, listname => $list->{'name'}}
);
$log->syslog(
'err',
'Could not change member email %s for list %s to %s because member is included',
$current_email,
$list,
$email
);
next;
}
# Check if user is already member of the list with their new address
......@@ -134,13 +132,16 @@ sub _twist {
foreach my $role ('owner', 'editor') {
foreach my $list (
Sympa::List::get_which($current_email, $robot_id, $role)) {
# Check if admin is included via an external datasource.
my ($admin_user) =
grep { $_->{role} eq $role and $_->{email} eq $current_email }
@{$list->get_current_admins || []};
if ($admin_user and defined $admin_user->{'inclusion'}) {
# Notify listmaster.
# Check the type of data sources.
# If only include_sympa_list of local mailing lists, then no
# problem. Otherwise, notify listmaster.
#FIXME: Consider the case source list is included from external
# data source.
if ($admin_user and defined $admin_user->{'inclusion_ext'}) {
Sympa::send_notify_to_listmaster(
$list,
'failed_to_change_included_admin',
......
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