File Coverage

blib/lib/Net/Lighthouse/Project.pm
Criterion Covered Total %
statement 95 137 69.3
branch 8 22 36.3
condition n/a
subroutine 26 29 89.6
pod 17 17 100.0
total 146 205 71.2


line stmt bran cond sub pod time code
1             package Net::Lighthouse::Project;
2 11     11   13575 use Any::Moose;
  11         1552658  
  11         80  
3 11     11   14010 use Net::Lighthouse::Util;
  11         62  
  11         393  
4 11     11   95 use Params::Validate ':all';
  11         23  
  11         2710  
5 11     11   8607 use Net::Lighthouse::Project::Ticket;
  11         30  
  11         567  
6 11     11   8875 use Net::Lighthouse::Project::TicketBin;
  11         33  
  11         417  
7 11     11   8682 use Net::Lighthouse::Project::Milestone;
  11         34  
  11         393  
8 11     11   8935 use Net::Lighthouse::Project::Message;
  11         51  
  11         469  
9 11     11   8768 use Net::Lighthouse::Project::Changeset;
  11         37  
  11         2137  
10              
11             extends 'Net::Lighthouse::Base';
12             # read only attr
13              
14             has [qw/created_at updated_at/] => (
15             isa => 'DateTime',
16             is => 'ro',
17             );
18              
19             has [qw/ open_states_list closed_states_list open_states closed_states /] => (
20             isa => 'ArrayRef',
21             is => 'ro',
22             auto_deref => 1,
23             );
24              
25             has [
26             qw/default_assigned_user_id default_milestone_id id open_tickets_count /] =>
27             (
28             isa => 'Maybe[Int]',
29             is => 'ro',
30             );
31             has [ qw/hidden send_changesets_to_events/ ] =>
32             (
33             isa => 'Bool',
34             is => 'ro',
35             );
36              
37             has [qw/description description_html permalink access license/] => (
38             isa => 'Maybe[Str]',
39             is => 'ro',
40             );
41              
42             # read&write attr
43             has [qw/archived public/] => (
44             isa => 'Bool',
45             is => 'rw',
46             );
47              
48             has [qw/name/] => (
49             isa => 'Str',
50             is => 'rw',
51             );
52              
53 11     11   102 no Any::Moose;
  11         30  
  11         53  
54             __PACKAGE__->meta->make_immutable;
55              
56             sub load {
57 1     1 1 464 my $self = shift;
58 1         33 validate_pos( @_, { type => SCALAR, regex => qr/^\d+|\w+$/ } );
59 1         31 my $id = shift;
60              
61 1 50       8 if ( $id !~ /^\d+$/ ) {
62              
63             # so we got a project name, let's find it
64 0         0 my ( $project ) = grep { $_->name eq $id } $self->list;
  0         0  
65 0 0       0 if ($project) {
66 0         0 $id = $project->id;
67             }
68             else {
69 0         0 die "can't find project $id in account " . $self->account;
70             }
71             }
72              
73 1         9 my $ua = $self->ua;
74 1         8 my $url = $self->base_url . '/projects/' . $id . '.xml';
75 1         6 my $res = $ua->get( $url );
76 1 50       49 if ( $res->is_success ) {
77 1         45 $self->load_from_xml( $res->content );
78             }
79             else {
80 0         0 die "try to get $url failed: "
81             . $res->status_line . "\n"
82             . $res->content;
83             }
84             }
85              
86             sub load_from_xml {
87 7     7 1 140 my $self = shift;
88 7         21 my $ref = $self->_translate_from_xml( shift );
89              
90             # dirty hack: some attrs are read-only, and Mouse doesn't support
91             # writer => '...'
92 7         42 for my $k ( keys %$ref ) {
93 133         318 $self->{$k} = $ref->{$k};
94             }
95 7         42 return $self;
96             }
97              
98             sub create {
99 0     0 1 0 my $self = shift;
100 0         0 validate(
101             @_,
102             {
103             name => { type => SCALAR },
104             archived => { optional => 1, type => BOOLEAN },
105             public => { optional => 1, type => BOOLEAN },
106             }
107             );
108 0         0 my %args = @_;
109              
110 0         0 my $xml = Net::Lighthouse::Util->translate_to_xml(
111             \%args,
112             root => 'project',
113             boolean => [qw/archived public/],
114             );
115              
116 0         0 my $ua = $self->ua;
117              
118 0         0 my $url = $self->base_url . '/projects.xml';
119              
120 0         0 my $request = HTTP::Request->new( 'POST', $url, undef, $xml );
121 0         0 my $res = $ua->request( $request );
122 0 0       0 if ( $res->is_success ) {
123 0         0 $self->load_from_xml( $res->content );
124 0         0 return 1;
125             }
126             else {
127 0         0 die "try to POST $url failed: "
128             . $res->status_line . "\n"
129             . $res->content;
130             }
131             }
132              
133             sub update {
134 0     0 1 0 my $self = shift;
135 0         0 validate(
136             @_,
137             {
138             archived => { optional => 1, type => BOOLEAN },
139             name => { optional => 1, type => SCALAR },
140             public => { optional => 1, type => BOOLEAN },
141             }
142             );
143 0         0 my %args = ( ( map { $_ => $self->$_ } qw/archived name public/ ), @_ );
  0         0  
144              
145 0         0 my $xml = Net::Lighthouse::Util->translate_to_xml(
146             \%args,
147             root => 'project',
148             boolean => [qw/archived public/],
149             );
150              
151 0         0 my $ua = $self->ua;
152 0         0 my $url = $self->base_url . '/projects/' . $self->id . '.xml';
153              
154 0         0 my $request = HTTP::Request->new( 'PUT', $url, undef, $xml );
155 0         0 my $res = $ua->request( $request );
156 0 0       0 if ( $res->is_success ) {
157 0         0 $self->load( $self->id ); # let's reload
158 0         0 return 1;
159             }
160             else {
161 0         0 die "try to PUT $url failed: "
162             . $res->status_line . "\n"
163             . $res->content;
164             }
165             }
166              
167             sub delete {
168 0     0 1 0 my $self = shift;
169 0         0 my $ua = $self->ua;
170 0         0 my $url = $self->base_url . '/projects/' . $self->id . '.xml';
171              
172 0         0 my $request = HTTP::Request->new( 'DELETE', $url );
173 0         0 my $res = $ua->request( $request );
174 0 0       0 if ( $res->is_success ) {
175 0         0 return 1;
176             }
177             else {
178 0         0 die "try to DELETE $url failed: "
179             . $res->status_line . "\n"
180             . $res->content;
181             }
182             }
183              
184             sub list {
185 3     3 1 17118 my $self = shift;
186 3         22 my $ua = $self->ua;
187 3         35 my $url = $self->base_url . '/projects.xml';
188 3         22 my $res = $ua->get( $url );
189 3 50       142 if ( $res->is_success ) {
190 3         148 my $ps = Net::Lighthouse::Util->read_xml( $res->content )->{projects}{project};
191 12         179 my @list = map {
192 3 50       26372 my $p = Net::Lighthouse::Project->new(
193 12         65 map { $_ => $self->$_ }
194 6         17 grep { $self->$_ } qw/account auth/
195             );
196 6         27 $p->load_from_xml($_);
197             } ref $ps eq 'ARRAY' ? @$ps : $ps;
198 3 100       51 return wantarray ? @list : \@list;
199             }
200             else {
201 0         0 die "try to get $url failed: "
202             . $res->status_line . "\n"
203             . $res->content;
204             }
205              
206             }
207              
208             sub initial_state {
209 1     1 1 3 my $self = shift;
210 1         8 my $ua = $self->ua;
211 1         4 my $url = $self->base_url . '/projects/new.xml';
212 1         5 my $res = $ua->get( $url );
213 1 50       45 if ( $res->is_success ) {
214 1         43 return $self->_translate_from_xml( $res->content );
215             }
216             else {
217 0         0 die "try to get $url failed: "
218             . $res->status_line . "\n"
219             . $res->content;
220             }
221             }
222              
223 1     1 1 757 sub tickets { return shift->_list( 'Ticket', @_ ) }
224 1     1 1 1999 sub ticket_bins { return shift->_list( 'TicketBin', @_ ) }
225 1     1 1 821 sub messages { return shift->_list( 'Message', @_ ) }
226 1     1 1 1407 sub milestones { return shift->_list( 'Milestone', @_ ) }
227 1     1 1 1009 sub changesets { return shift->_list( 'Changeset', @_ ) }
228              
229 1     1 1 31969 sub ticket { return shift->_new( 'Ticket' ) }
230 1     1 1 1161 sub ticket_bin { return shift->_new( 'TicketBin' ) }
231 1     1 1 828 sub message { return shift->_new( 'Message' ) }
232 1     1 1 776 sub milestone { return shift->_new( 'Milestone' ) }
233 1     1 1 797 sub changeset { return shift->_new( 'Changeset' ) }
234              
235             sub _new {
236 5     5   11 my $self = shift;
237 5         122 validate_pos(
238             @_,
239             {
240             type => SCALAR,
241             regex => qr/^(TicketBin|Ticket|Message|Changeset|Milestone)$/,
242             }
243             );
244 5         68 my $class = 'Net::Lighthouse::Project::' . shift;
245 10         93 my $object = $class->new(
246             project_id => $self->id,
247 10         61 map { $_ => $self->$_ }
248 5         20 grep { $self->$_ } qw/account auth/
249             );
250 5         866 return $object;
251             }
252              
253             sub _list {
254 5     5   9 my $self = shift;
255 5         122 validate_pos(
256             @_,
257             {
258             type => SCALAR,
259             regex => qr/^(TicketBin|Ticket|Message|Changeset|Milestone)$/,
260             },
261             (0)x(@_-1)
262             );
263 5         61 my $class = 'Net::Lighthouse::Project::' . shift;
264 10         171 my $object = $class->new(
265             project_id => $self->id,
266 10         30 map { $_ => $self->$_ }
267 5         18 grep { $self->$_ } qw/account auth/
268             );
269 5         36 return $object->list(@_);
270             }
271              
272             sub _translate_from_xml {
273 8     8   182 my $self = shift;
274 8         48 my $ref = Net::Lighthouse::Util->translate_from_xml(shift);
275 8         19 for (qw/open_states_list closed_states_list/) {
276 16         100 $ref->{$_} = [ split /,/, $ref->{$_} ];
277             }
278              
279 8         17 for my $states (qw/ open_states closed_states /) {
280 16         69 my @values = split /\n/, $ref->{$states};
281 16         25 my @new_values;
282 16         22 for my $value (@values) {
283             # e.g. new/f17 # You can add comments here
284 40 50       170 if ( $value =~ m{(\w+)(?:/(\w+))?\s+#?\s*(.*)?} ) {
285 40         249 push @new_values, { name => $1, color => $2, comment => $3 };
286             }
287             else {
288 0         0 warn "parse $value failed";
289             }
290             }
291 16         60 $ref->{$states} = [@new_values];
292             }
293 8         22 return $ref;
294             }
295              
296             1;
297              
298             __END__