Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 162 additions & 2 deletions lib/Sendinblue/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,168 @@ sub add_contact {
} else {
warn "Post $uri failed: " . $response->status_line;
return {};
}
}

# manage lists:
sub delete_from_list {
my ($self, $list_id, $emails) = @_;

return if !$emails || !@$emails;

my $uri = $self->_construct_uri("contacts/lists/$list_id/contacts/remove");
my @elist = @$emails;
my @sublist = ();
my $response;
if (scalar @$emails > 100) {
my $total = scalar @$emails;
while (@elist) {
@sublist = splice(@elist, 0, 99);
$response = $self->ua->post(
$uri,
Content => encode_json(
{
emails => \@sublist,
}),
%{ $self->headers },
);
sleep 1;
}
} else {
$response = $self->ua->post(
$uri,
Content => encode_json(
{
emails => $emails,
}),
%{ $self->headers },
);
}
if($response->is_success) {
if ($response->code == 201) {
return 1;
} else {
return decode_json $response->decoded_content;
}
} else {
warn "Post $uri failed: " . $response->status_line;
return {};
}
}

sub add_to_list {
my ($self, $list_id, $emails) = @_;

return if !$emails || !@$emails;

my $uri = $self->_construct_uri("contacts/lists/$list_id/contacts/add");
my @elist = @$emails;
my @sublist = ();
my $response;
if (scalar @$emails > 100) {
my $total = scalar @$emails;
while (@elist) {
@sublist = splice(@elist, 0, 99);
$response = $self->ua->post(
$uri,
Content => encode_json(
{
emails => \@sublist,
}),
%{ $self->headers },
);
sleep 1;
}
} else {
$response = $self->ua->post(
$uri,
Content => encode_json(
{
emails => $emails,
}),
%{ $self->headers },
);
}

if($response->is_success) {
if ($response->code == 201) {
return 1;
} else {
return decode_json $response->decoded_content;
}
} else {
warn "Post $uri failed: " . $response->status_line;
return {};
}
}

# New API replaces bulk/batch update?
# One call per set of ListIds? (cant attach listids to contacts, its now
# list of contacts for.. set of listids
# Cant do unlinkListIds, that only seems to be available on individual contact
# update now.. :(
# https://developers.brevo.com/reference/import-contacts

sub import_contacts {
my ($self, $contacts, $list_ids) = @_;

return if !@$contacts;
# no modifiedAt / createdAt
# only one of email/id/sms
foreach my $c (@$contacts) {
delete $c->{modifiedAt};
delete $c->{createdAt};
# delete $c->{email};
delete $c->{sms};
}

my $uri = $self->_construct_uri('contacts/import');
print STDERR Dumper($contacts);

my @clist = @$contacts;
my @sublist = @$contacts;
my $response;
if (scalar @$contacts > 100) {
my $total = scalar @$contacts;
while (@clist) {
@sublist = splice(@clist, 0, 99);

$response = $self->ua->post(
$uri,
Content => encode_json(
{
# updateExistingContacts => defaults to true
# body, list of objs with email and attributes
jsonBody => \@sublist,
listIds => $list_ids, #lists to add to
}),
%{ $self->headers },
);
# print STDERR "Update Contacts:", Dumper( $response);
sleep 1;
}
} else {
$response = $self->ua->post(
$uri,
Content => encode_json(
{
jsonBody => $contacts,
listIds => $list_ids, #lists to add to
}),
%{ $self->headers },
);
# print STDERR "Update Contacts:", Dumper( $response);
}
if($response->is_success) {
if ($response->code == 204) {
return 1;
} else {
return decode_json $response->decoded_content;
}
} else {
warn "Post $uri failed: " . $response->status_line;
return {};
}

}

sub update_contacts {
Expand Down Expand Up @@ -164,7 +324,7 @@ sub delete_contact {

my $uri = $self->_construct_uri('contacts/' . $contact->{id});
my $response = $self->ua->delete($uri, %{ $self->headers });
if ($response->is_sucess) {
if ($response->is_success) {
return 1;
} else {
warn "Delete $uri failed: " . $response->status_line;
Expand Down
105 changes: 79 additions & 26 deletions script/sendinblue.pl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
# Filter just in case we have others:
my @people = grep { any {$_ == $all_people_id} (@{$_->{listIds}}) } (@$contacts);
print "Found " . scalar @people . " people in All People\n";
print "Found " . scalar @$contacts . " people in Contacts\n";

my %contacts_check = map { $_->{email} && lc $_->{email} => 1 } @$contacts;

# Compare to db people:
my $db_people = $schema->resultset('Person')->search_rs({} );
Expand All @@ -53,62 +56,113 @@
my @updates = ();
my @checked_emails = ();

foreach my $person (@people) {
my $db_person = $db_people->search({ '-and' => [
end_date => undef,
\['LOWER(email) = ?', lc($person->{email})], #
]});
# email => { '-ilike' => $person->{email} }, end_date => undef });
# gather: people in list:
my $add_valid = [];
my $rem_valid = [];
my $add_news_events = [];
my $rem_news_events = [];

# Bulk update all with "all people" list, update/delete from single lists for the rest?

foreach my $person (@$contacts) {
my $db_person = $db_people->search(\['LOWER(email) = ?', lc($person->{email})]); #
# my $db_person = $db_people->search({ '-and' => [
# end_date => undef,
# \['LOWER(email) = ?', lc($person->{email})], #
# ]});
# # email => { '-ilike' => $person->{email} }, end_date => undef });
# if ($person->{email} =~ /hunter/) {
# $DB::single=1;
# }
if ($db_person->count == 1) {
$db_person = $db_person->first;
if (($person->{attributes}{NAME} ne $db_person->name
|| ($person->{attributes}{OPT_IN} != $db_person->opt_in)
|| (($person->{attributes}{JOINED} || '') ne $db_person->created_date->date)
|| ($db_person->valid_until && $person->{attributes}{PAID_UP_UNTIL} ne $db_person->real_expiry($localconfig{overlap_days})->date))) {
# delete $person->{listIds};
# if (($person->{attributes}{NAME} ne $db_person->name
# || ($person->{attributes}{OPT_IN} != $db_person->opt_in)
# || (($person->{attributes}{JOINED} || '') ne $db_person->created_date->date)
# || ($db_person->valid_until && $person->{attributes}{PAID_UP_UNTIL} ne $db_person->real_expiry($localconfig{overlap_days})->date))) {
#change list prefs:
# turned on opt-in, add events+newsletter
if (!$person->{attributes}{OPT_IN} && $db_person->opt_in) {
push @{ $person->{listIds} }, $events_id, $newsletter_id;
if ($db_person->opt_in && !grep { $_ == $newsletter_id} @{$person->{listIds}}) {
push @$add_news_events, $person->{email};
}
# turned off opt-in, remove em again
if ($person->{attributes}{OPT_IN} && !$db_person->opt_in) {
$person->{listIds} = [ grep { $_ != $events_id && $_ != $newsletter_id } (@{ $person->{listIds} }) ];
if (!$db_person->opt_in && grep { $_ == $newsletter_id} @{$person->{listIds}}) {
push @$rem_news_events, $person->{email};
}
# no longer a paid-up member
print STDERR $db_person->name, Data::Dumper::Dumper($person->{listIds});
if (!$db_person->valid_until || $db_person->real_expiry($localconfig{overlap_days}) < DateTime->now) {
$person->{listIds} = [ grep { $_ != $valid_all_id } (@{ $person->{listIds} }) ];
print STDERR $db_person->name, "List Ids changed ", Data::Dumper::Dumper($person->{listIds});
push @{$person->{unlinkListIds}}, $valid_all_id;
if ((!$db_person->valid_until || $db_person->real_expiry($localconfig{overlap_days}) < DateTime->now) && grep { $_ == $valid_all_id} @{$person->{listIds}}) {
push @$rem_valid, $person->{email};
# print STDERR $db_person->name, "List Ids changed ", Data::Dumper::Dumper($person->{listIds});
# push @{$person->{unlinkListIds}}, $valid_all_id;
}
# is a paid-up member again
if ($db_person->valid_until && $db_person->real_expiry($localconfig{overlap_days}) >= DateTime->now) {
push @{ $person->{listIds} }, $valid_all_id;
print STDERR $db_person->name, "List Ids changed again?", Data::Dumper::Dumper($person->{listIds});
if (($db_person->valid_until && $db_person->real_expiry($localconfig{overlap_days}) >= DateTime->now) && !grep { $_ == $valid_all_id} @{$person->{listIds}}) {
push @$add_valid, $person->{email};
# print STDERR $db_person->name, "List Ids changed again?", Data::Dumper::Dumper($person->{listIds});
}


if (!$db_person->end_date &&
($person->{attributes}{NAME} ne $db_person->name
|| ($person->{attributes}{OPT_IN} != $db_person->opt_in)
|| (($person->{attributes}{JOINED} || '') ne $db_person->created_date->date)
|| ($db_person->valid_until && $person->{attributes}{PAID_UP_UNTIL} ne $db_person->real_expiry($localconfig{overlap_days})->date))) {
$person->{attributes}{NAME} = $db_person->name;
$person->{attributes}{JOINED} = $db_person->created_date->date;
$person->{attributes}{OPT_IN} = $db_person->opt_in ? JSON::true : JSON::false;
if ($db_person->real_expiry($localconfig{overlap_days})) {
$person->{attributes}{PAID_UP_UNTIL} = $db_person->real_expiry($localconfig{overlap_days})->date;
}

push @updates, $person;
}
} else {
# If can't find the email in our db then presumably they changed their
# Email, remove from any lists
foreach my $lId (@{$person->{listIds}}) {
if ($lId == $valid_all_id) {
push @$rem_valid, $person->{email};
}
# if ($lId == $events_id) {
# push @$rem_news_events, $person->{email};
# }
}
}
push @checked_emails, $person->{email};
}
# All changed members:
print "Updating " . scalar @updates . " people statuses in Sendinblue\n";
# print STDERR Dumper(\@updates);
$sb->update_contacts(\@updates);
if (@updates) {
$sb->import_contacts(\@updates, [$all_people_id]);
}
# remove from news_events/valid:
if (@$rem_news_events) {
$sb->delete_from_list($events_id, $rem_news_events);
$sb->delete_from_list($newsletter_id, $rem_news_events);
}
if (@$rem_valid) {
$sb->delete_from_list($valid_all_id, $rem_valid);
}
# add to news,events,valid:
if (@$add_news_events) {
$sb->add_to_list($events_id, $add_news_events);
$sb->add_to_list($newsletter_id, $add_news_events);
}
if (@$add_valid) {
$sb->add_to_list($valid_all_id, $add_valid);
}

# New members:
my $new_members = $db_people->search({ email => { '-not_in' => [map { lc($_) } @checked_emails] }, end_date => undef });
#my @not_in = map { lc($_) } @checked_emails;
# Don't add any contacts that are already in the system
my @not_in = keys %contacts_check;
my $new_members = $db_people->search({ email => { '-not_in' => \@not_in }, end_date => undef });
print "Adding " . $new_members->count . " new members into Sendinblue\n";

while (my $person = $new_members->next) {
# not_in is case sensitive, sigh
next if $contacts_check{lc $person->email};
$sb->add_contact({
email => $person->email,
listIds => [ $all_people_id, ($person->opt_in ? ($events_id, $newsletter_id) : ()), ( $person->valid_until && $person->valid_until >= DateTime->now ? ($valid_all_id) : ()) ],
Expand All @@ -130,7 +184,6 @@

print "Would remove " . scalar @gone_people . " members who left from Sendinblue\n";
# print STDERR Dumper(\@gone_people);
exit;
foreach my $person (@gone_people) {
$sb->delete_contact($person);
}
Expand Down
Loading