1package App::SD::Replica::lighthouse;
2use Any::Moose;
3extends qw/App::SD::ForeignReplica/;
4
5use Params::Validate qw(:all);
6use Memoize;
7
8use URI;
9use Memoize;
10
11use Prophet::ChangeSet;
12
13use constant scheme => 'lighthouse';
14use constant pull_encoder => 'App::SD::Replica::lighthouse::PullEncoder';
15use constant push_encoder => 'App::SD::Replica::lighthouse::PushEncoder';
16
17has lighthouse => ( isa => 'Net::Lighthouse::Project', is => 'rw' );
18has remote_url => ( isa => 'Str',                      is => 'rw' );
19has account    => ( isa => 'Str',                      is => 'rw' );
20has project    => ( isa => 'Str',                      is => 'rw' );
21has query      => ( isa => 'Str',                      is => 'rw' );
22
23our %PROP_MAP = ( state => 'status', title => 'summary' );
24
25sub BUILD {
26    my $self = shift;
27
28    eval {
29        require Net::Lighthouse::Project;
30        require Net::Lighthouse::User;
31    };
32    if ($@) {
33        die "SD requires Net::Lighthouse to sync with a Lighthouse server.\n".
34        "'cpan Net::Lighthouse' may sort this out for you";
35    }
36
37
38    my ( $auth, $account, $project, $query ) =
39      $self->{url} =~ m{^lighthouse:(?:(.*)@)?(.*?)/(.*?)(?:/(.*))?$}
40      or die
41"Can't parse lighthouse server spec. Expected lighthouse:email:password\@account/project/query or lighthouse:token\@account/project/query.";
42    my $server = "http://$account.lighthouseapp.com";
43    $self->query( $query || 'all' );
44
45    my ( $email, $password, $token );
46    if ($auth) {
47        if ( $auth =~ /@/ ) {
48            ( $email, $password ) = split /:/, $auth;
49        }
50        else {
51            $token = $auth;
52        }
53    }
54
55    unless ( $token || $password ) {
56        if ($email) {
57            ( undef, $password ) = $self->prompt_for_login(
58                uri            => $server,
59                username       => $email,
60            );
61        }
62        else {
63            ( undef, $token ) = $self->prompt_for_login(
64                uri           => $server,
65                username      => 'not important',
66                secret_prompt => sub {
67                    "token for $server: ";
68                }
69            );
70        }
71    }
72
73    $self->remote_url($server);
74    $self->account( $account );
75    $self->project( $project );
76
77    my $lighthouse = Net::Lighthouse::Project->new(
78        auth => {
79            $email ? ( email => $email, password => $password ) : (),
80            $token ? ( token => $token ) : (),
81        },
82        account => $account,
83    );
84    $lighthouse->load( $project );
85    $self->lighthouse( $lighthouse );
86}
87
88
89sub get_txn_list_by_date {
90    my $self   = shift;
91    my $ticket = shift;
92    my $ticket_obj = $self->lighthouse->ticket;
93    $ticket_obj->load($ticket);
94
95    my $sequence = 0;
96    my @txns = map {
97        {
98            id      => $sequence++,
99            creator => $_->creator_name,
100            created => $_->created_at->epoch,
101        }
102    } $ticket_obj->versions;
103
104    if ( $ticket_obj->attachments ) {
105        my $user = Net::Lighthouse::User->new(
106            map { $_ => $self->sync_source->lighthouse->$_ }
107              grep { $self->sync_source->lighthouse->$_ }
108              qw/account email password token/
109        );
110        for my $att ( $ticket_obj->attachments ) {
111            $user->load( $att->uploader_id );
112            push @txns,
113              {
114                id      => $att->id,
115                creator => $user->name,
116                created => $att->created_at->epoch,
117              };
118        }
119        @txns = sort { $a->created <=> $b->created } @txns;
120    }
121    return @txns;
122}
123
124sub foreign_username {
125    my $self = shift;
126    my $user =
127      Net::Lighthouse::User->new( map { $_ => $self->lighthouse->$_ }
128          grep { $self->lighthouse->$_ } qw/account email password token/ );
129
130    if ( $user->token ) {
131        # so we use token, let's try to find user's name
132        require Net::Lighthouse::Token;
133        my $token = Net::Lighthouse::Token->new(
134            map { $_ => $self->lighthouse->$_ }
135              grep { $self->lighthouse->$_ } qw/account token/
136        );
137        $token->load( $self->lighthouse->token );
138        my $user = Net::Lighthouse::User->new(
139            map { $_ => $self->lighthouse->$_ }
140              grep { $self->lighthouse->$_ } qw/account token/
141        );
142        $user->load( $token->user_id );
143        return $user->name;
144    }
145    else {
146        # TODO we can't get user's name via email :/
147        # wish they augment the api so we can load via email
148        return $1 if $user->email =~ /(.*?)@/;
149    }
150}
151
152sub _uuid_url {
153    my $self = shift;
154    Carp::cluck "- can't make a uuid for this" unless ($self->remote_url && $self->account && $self->project );
155    return  join( '/', $self->remote_url, $self->project );
156}
157
158sub remote_uri_path_for_comment {
159    my $self = shift;
160    my $id = shift;
161    return "/comment/".$id;
162}
163
164sub remote_uri_path_for_id {
165    my $self = shift;
166    my $id = shift;
167    return "/ticket/".$id;
168}
169
170sub database_settings {
171    my $self = shift;
172    return {
173        project_name    => $self->account . '/' . $self->project,
174        active_statuses => [ $self->lighthouse->open_states_list ],
175        statuses        => [
176            @{ $self->lighthouse->open_states_list },
177            @{ $self->lighthouse->closed_states_list }
178        ],
179        milestones => [ '', map { $_->title } $self->lighthouse->milestones ],
180        default_milestone => '',
181    };
182
183}
184
185__PACKAGE__->meta->make_immutable;
186no Any::Moose;
1871;
188