Group
Extension

Yandex-Audience/lib/Yandex/Audience.pm

=pod

=encoding utf-8

=head1 NAME

B<Yandex::Audience> - a simple API for Yandex.Audience

It contains very few number of API-calls now.

=head1 VERSION

version 0.01

=head1 SYNOPSYS

  use Yandex::Audience;

  my $Token = 'AgAAAAAAELGSBIXHdBAPDm-6sJ7Sbao7J-pmaU7'; #Auth token
  my $YaAudience= Yandex::Audience->new( -token => $Token);

  #Get list of existing segments
  my $Segments = $YaAudience->getListOfSegments();

  #Upload a content of String in CSV-fromat
  my $Segment = $YaAudience->uploadCSV($CSV);

  #Upload CSV-file
  my $Segment = $YaAudience->uploadCSV('real1500_md5.csv');

  #Save the uploaded content as a segment
  my $SegmentStatus = $YaAudience->saveSegment( segment => $Segment->{id},
                                                name => 'Litres'.$Segment->{id},
                                                hashed => 1,
                                               ) if exists $Segment->{id};

  #Delete a segment
  my $Result = $YaAudience->deleteSegment(9243581);

=head1 METHODS

=cut

package Yandex::Audience;
use strict;
use warnings;
use utf8;
use Carp qw(croak);
use LWP::UserAgent;
use HTTP::Request::Common qw(POST);
use JSON::XS;
use File::Basename;

use constant APIVERSION => 1;
use constant BASEURL => 'https://api-audience.yandex.ru/v';

our $VERSION    = '0.01';

sub new {
  my $class = shift;
  my %opt = @_;
  my $self = {};
  $self->{token} = $opt{token} || croak "Specify token param";
  $self->{timeout} = 10; #For LWP::UserAgent

  my $ua = LWP::UserAgent->new();
  $ua->timeout($self->{timeout});
  $ua->default_header(Authorization  => 'OAuth ' . $self->{token});
  $ua->default_header('Content-Type' => 'application/json');
  $self->{ua} = $ua;

  bless $self, $class;
  return $self;
}

=head2 getListOfSegments()

Returns a list of existing segments available to the user.

  my $Segments = $YaAudience->get_list_of_segments();

=cut

sub getListOfSegments {
  my $self = shift;
  my $url = &BASEURL . &APIVERSION . '/management/segments';

  my $response = $self->{ua}->get($url);
  return undef unless $response->is_success && $response->content;
  
  my $json;
  eval {
    $json = JSON::XS->new->utf8->decode( $response->content );
  };
  return undef if $@;

  if (exists $json->{segments}) {
    for my $Segment (@{$json->{segments}}) {
      $self->_prepareJSON($Segment);
    }
  }
  return $json->{segments};
}

=head2 uploadCSV()

Upload a CSV-file with data and create a segment.
Returns Hash with Id of segment(s) and it's statuses.

  my $Segment = $YaAudience->uploadCSV('real1500_md5.csv');

=cut

sub uploadCSV {
  my $self = shift;
  my $file = shift;
  
  my $url = &BASEURL . &APIVERSION . '/management/segments/upload_csv_file';
  my $request;
  if (!chomp $file && -e $file) {
    $request = POST ($url, Content_Type  => 'form-data', Content => ['file', [$file]]);
  } else {
    $request = POST ($url, Content_Type  => 'form-data', Content => [file =>  [undef, 'crm.csv', Content=>$file, Content_Type => 'text/csv'] ]);
  }
  my $response = $self->{ua}->request($request);

  return undef unless $response->is_success && $response->content;

  my $json;
  eval {
    $json = JSON::XS->new->utf8->decode( $response->content );
  };
  return undef if $@;
  
  $self->_prepareJSON($json->{segment}) if exists $json->{segment};
  return $json->{segment};
}

=head2 saveSegment()

Saves a segment generated from a file with user data.

  my $SegmentStatus = $YaAudience->saveSegment( -segment => $Segment->{id},          #Id of a segment
                                                 -name   => 'Litres'.$Segment->{id}, #A name of a segment
                                                 -hashed => 1,                       #1 if data contains hashed fields
                                               ) if exists $Segment->{id};

=cut

sub saveSegment {
  my $self = shift;
  my %opt = @_;
  my $SegmentID = $opt{segment} || Carp::carp('id of a segment must be defined');
  my $SegmentName = exists $opt{name} ? $opt{name} : 'Segment' . $SegmentID;
  my $SegmentType = exists $opt{type} ? $opt{type} : 'crm';
  my $IsHashed = exists $opt{hashed} && $opt{hashed} ? 1 : 0;
  
  my $url = &BASEURL . &APIVERSION . '/management/segment/' . $SegmentID . '/confirm';

  my %JSON = (
    segment => {
      id           => $SegmentID,
      name         => $SegmentName,
      hashed       => $IsHashed,
      content_type => $SegmentType,
    }
  );

  my $response = $self->{ua}->post( $url, Content => encode_json(\%JSON) );

  return undef unless $response->is_success && $response->content;

  my $json;
  eval {
    $json = JSON::XS->new->utf8->decode( $response->content );
  };
  return undef if $@;
  
  $self->_prepareJSON($json->{segment}) if exists $json->{segment};
  return $json->{segment};

  return 1;
}

=head2 deleteSegment()

Deletes the specified segment (or segments)
Returns arrayref to scalars: 1 if success, 0 otherwise.

  my $Result = $YaAudience->deleteSegment($SegmentID); #$SegmentID - can be scalar or arrayref to scalars, or arrayref to hashes with id of segment(s).
or
  my $Result = $YaAudience->deleteSegment( [9254200, 9254215] );
=cut

sub deleteSegment {
  my $self = shift;
  my $SegmentID = shift // Carp::carp('id of the segment must be defined');
  my @Result;
  
  if (ref $SegmentID eq 'ARRAY') {
    if (ref $SegmentID->[0] eq 'HASH' && exists $SegmentID->[0]->{id}) { #Perhaps it's array with structures of `yandex.segment` type
      for (@$SegmentID) {
        push @Result, $self->_deleteSegment($_->{id});
      }
    } else { #It must be array of scalars
      for (@$SegmentID) {
        push @Result, $self->_deleteSegment($_);
      }
    }
  } else { #It must be scalar
    return $self->_deleteSegment($SegmentID);
  }
  return \@Result;
}

=head2 _deleteSegment()

The internal method. Deletes a segment.
Returns scalar: 1 if success, 0 otherwise.

  my $Result = $YaAudience->_deleteSegment($SegmentID); #$SegmentID - scalar, contains id of segment.
  
=cut
  
sub _deleteSegment {
  my $self = shift;
  my $SegmentID = shift // Carp::carp('id of the segment must be defined');

  my $url = &BASEURL . &APIVERSION . '/management/segment/' . $SegmentID;
  my $response = $self->{ua}->delete($url);
  
  return 0 unless $response->is_success && $response->content;
  
  my $json;
  eval {
    $json = JSON::XS->new->utf8->decode( $response->content );
  };
  return undef if $@;
  return $json->{success} eq JSON::XS::true ? 1 : 0;
}

=head2 _prepareJSON()

The internal method. Returns hash with values of type JSON::Boolean changed to Scalars (1 and 0).

=cut

sub _prepareJSON {
  my $self = shift;
  my $json = shift;
  
  for (keys %{$json}) {
    if (JSON::XS::is_bool($json->{$_})) {
      $json->{$_} = ($json->{$_} eq JSON::XS::true) ? 1 : 0;
    }
  }
  return $json;
}

=head1 AUTHOR

Dmitry Marin, C<< <mcorvax at cpan.org> >>


=head1 BUGS

Please report any bugs or feature requests to C<bug-yandex-audience at rt.cpan.org>, or through
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Yandex-Audience>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.


=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Yandex::Audience


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Yandex-Audience>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Yandex-Audience>

=item * CPAN Ratings

L<https://cpanratings.perl.org/d/Yandex-Audience>

=item * Search CPAN

L<https://metacpan.org/release/Yandex-Audience>

=back


=head1 LICENSE AND COPYRIGHT

This software is Copyright (c) 2019 by Dmitry Marin.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)

=cut

1; # End of Yandex::Audience

Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.