App-SD

 view release on metacpan or  search on metacpan

lib/App/SD/Replica/hm.pm  view on Meta::CPAN

use Any::Moose;
extends 'App::SD::ForeignReplica';
use Params::Validate qw(:all);
use Memoize;
use Prophet::ChangeSet;
use File::Temp 'tempdir';
use Carp;
use Try::Tiny;

has hm               => ( isa => 'Net::Jifty', is => 'rw' );
has remote_url       => ( isa => 'Str',        is => 'rw' );
has foreign_username => ( isa => 'Str',        is => 'rw' );
has props            => ( isa => 'HashRef',    is => 'rw' );

use constant scheme       => 'hm';
use constant pull_encoder => 'App::SD::Replica::hm::PullEncoder';
use constant push_encoder => 'App::SD::Replica::hm::PushEncoder';

# XXX TODO - kill the query requirement by refactoring sub run in the superclass
use constant query => '';

=head2 BUILD

Open a connection to the source identified by C<$self->{url}>.

=cut

# XXX: this should be called from superclass, or better, have individual attributes have their own builders.

sub BUILD {
    my $self = shift;

    # Require rather than use to defer load
    try {
        require Net::Jifty;
    } catch {
        die "SD requires Net::Jifty to sync with a Hiveminder server.\n".
        "'cpan Net::Jifty' may sort this out for you";
    };

    my ( $server, $props ) = $self->{url} =~ m/^hm:(.*?)(?:\|(.*))?$/
        or die
        "Can't parse Hiveminder server spec. Expected hm:http://hiveminder.com or hm:http://hiveminder.com|props";

    my ($username, $password) = $self->extract_auth_from_uri($server);

    if ( $password ) {
        try {
            $self->_hiveminder_login($username, $password);
        } catch {
            die "Bad username or password specified in URL! ".
                "Error message was:\n".
                _hiveminder_clean_login_error($_);
        };
    }
    else {
        ($username, $password) = $self->login_loop(
            uri      => $self->remote_url,
            username => $username,
            # remind the user that hiveminder logins are email addresses
            username_prompt => sub {
                my $uri = shift;
                return "Login email for $uri: ";
            },
            login_callback => \&_hiveminder_login,
            catch_callback => sub {
                my ($verbose_error) = @_;
                warn _hiveminder_clean_login_error($verbose_error);
            },
        );
    }
    $self->foreign_username($username);

    if ($props) {
        my %props = split /=|;/, $props;
        $self->props( \%props );
    }
}

sub _hiveminder_login {
    my ($self, $username, $password) = @_;
    $self->hm(
        Net::Jifty->new(
            site        => $self->remote_url,
            cookie_name => 'JIFTY_SID_HIVEMINDER',
            email    => $username,
            password => $password
        )
    );
}

sub _hiveminder_clean_login_error {
    my $verbose_error = shift;
    # Net::Jifty uses Carp::confess to deal with login problems :(
    my $error_message = (split /\n/, $verbose_error)[0];
    $error_message =~ s/ at .* line [0-9]+$//;
    return "\n$error_message\n\n";
}

sub request_failed {
    my ($self, $response) = @_;

    return defined($response->{success}) && $response->{success} == 0;
}

sub decode_error {
    my $self   = shift;
    my $status = shift;
    my $msg    = '';
    $msg .= $status->{'error'} if defined $status->{'error'};
    if ( $status->{'field_errors'} ) {
        while ( my ( $k, $v ) = each %{ $status->{'field_errors'} } ) {
            $msg .= "field '$k' - '$v'\n";
        }
    }
    return $msg;
}

=head2 _uuid_url

Return the replica's UUID



( run in 1.423 second using v1.01-cache-2.11-cpan-6aa56a78535 )