File Coverage

blib/lib/WebService/PivotalTracker/Story.pm
Criterion Covered Total %
statement 31 67 46.2
branch 0 2 0.0
condition n/a
subroutine 11 19 57.8
pod 3 3 100.0
total 45 91 49.4


line stmt bran cond sub pod time code
1             package WebService::PivotalTracker::Story;
2              
3 1     1   6 use strict;
  1         3  
  1         23  
4 1     1   5 use warnings;
  1         1  
  1         19  
5 1     1   5 use namespace::autoclean;
  1         2  
  1         4  
6              
7             our $VERSION = '0.12';
8              
9 1     1   62 use Params::ValidationCompiler qw( validation_for );
  1         2  
  1         57  
10 1     1   348 use WebService::PivotalTracker::Comment;
  1         4  
  1         31  
11 1     1   451 use WebService::PivotalTracker::Label;
  1         3  
  1         32  
12 1     1   544 use WebService::PivotalTracker::Person;
  1         4  
  1         34  
13 1     1   7 use WebService::PivotalTracker::PropertyAttributes;
  1         2  
  1         53  
14 1         23 use WebService::PivotalTracker::Types qw(
15             ArrayRef CommentObject DateTimeObject LabelObject Maybe
16             NonEmptyStr Num PersonObject PositiveInt Str StoryState StoryType Uri
17 1     1   6 );
  1         1  
18              
19 1     1   1908 use Moo;
  1         2  
  1         5  
20              
21             my %props = (
22             id => PositiveInt,
23             project_id => PositiveInt,
24             name => NonEmptyStr,
25             description => Str,
26             story_type => StoryType,
27             current_state => StoryState,
28             estimate => Maybe [Num],
29             accepted_at => {
30             type => DateTimeObject,
31             inflator => '_inflate_iso8601_datetime',
32             },
33             deadline => {
34             type => DateTimeObject,
35             inflator => '_inflate_iso8601_datetime',
36             },
37             requested_by_id => PositiveInt,
38             owner_ids => ArrayRef [PositiveInt],
39             task_ids => {
40             type => ArrayRef [PositiveInt],
41             default => sub { [] },
42             },
43             follower_ids => {
44             type => ArrayRef [PositiveInt],
45             default => sub { [] },
46             },
47             created_at => {
48             type => DateTimeObject,
49             inflator => '_inflate_iso8601_datetime',
50             },
51             updated_at => {
52             type => DateTimeObject,
53             inflator => '_inflate_iso8601_datetime',
54             },
55             url => {
56             type => Uri,
57             inflator => '_inflate_uri',
58             },
59             kind => NonEmptyStr,
60             );
61              
62             has( @{$_} ) for props_to_attributes(%props);
63              
64             has comments => (
65             is => 'ro',
66             isa => ArrayRef [CommentObject],
67             init_arg => undef,
68             lazy => 1,
69             builder => '_build_comments',
70             clearer => '_clear_comments',
71             );
72              
73             has labels => (
74             is => 'ro',
75             isa => ArrayRef [LabelObject],
76             init_arg => undef,
77             lazy => 1,
78             builder => '_build_labels',
79             clearer => '_clear_labels',
80             );
81              
82             has requested_by => (
83             is => 'ro',
84             isa => PersonObject,
85             lazy => 1,
86             default => sub {
87             my $self = shift;
88             WebService::PivotalTracker::Person->new(
89             raw_content => $self->raw_content->{requested_by},
90             pt_api => $self->_pt_api,
91             );
92             },
93             );
94              
95             with 'WebService::PivotalTracker::Entity';
96              
97             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
98             sub _properties {
99 2     2   28 return %props;
100             }
101             ## use critic
102              
103             {
104             my $check = validation_for(
105             params => {
106             current_state => { type => StoryState },
107             }
108             );
109              
110             sub update {
111 0     0 1   my $self = shift;
112 0           my %args = $check->(@_);
113              
114 0           my $raw = $self->_client->put( $self->_self_uri, \%args );
115              
116 0           return ( ref $self )->new(
117             raw_content => $raw,
118             pt_api => $self->_pt_api,
119             );
120             }
121             }
122              
123             {
124             my $check = validation_for(
125             params => {
126             person_id => {
127             type => PositiveInt,
128             optional => 1,
129             },
130             text => { type => NonEmptyStr },
131             }
132             );
133              
134             sub add_comment {
135 0     0 1   my $self = shift;
136 0           my %args = $check->(@_);
137              
138 0           my $comment = WebService::PivotalTracker::Comment->new(
139             raw_content =>
140             $self->_client->post( $self->_comments_uri, \%args ),
141             pt_api => $self->_pt_api,
142             );
143 0           $self->_clear_comments;
144              
145 0           return $comment;
146             }
147             }
148              
149             # We could fetch each id in $self->comment_ids one at a time, but there's an
150             # endpoint to get all the comments at once, which is going to be more
151             # efficient.
152             sub _build_comments {
153 0     0     my $self = shift;
154              
155 0           my $raw_comments = $self->_client->get( $self->_comments_uri );
156              
157             return [
158             map {
159 0           WebService::PivotalTracker::Comment->new(
160             raw_content => $_,
161             pt_api => $self->_pt_api,
162             )
163 0           } @{$raw_comments}
  0            
164             ];
165             }
166              
167             sub _comments_uri {
168 0     0     my $self = shift;
169              
170 0           my $path = sprintf(
171             '/projects/%s/stories/%s/comments',
172             $self->project_id,
173             $self->id,
174             );
175              
176 0           return $self->_client->build_uri($path);
177             }
178              
179             before _clear_comments => sub {
180             my $self = shift;
181             delete $self->raw_content->{comments};
182             };
183              
184             {
185             my $check = validation_for(
186             params => {
187             name => { type => NonEmptyStr },
188             }
189             );
190              
191             sub add_label {
192 0     0 1   my $self = shift;
193 0           my %args = $check->(@_);
194              
195 0           $self->_client->post( $self->_labels_uri, \%args );
196 0           $self->_clear_labels;
197              
198 0           return;
199             }
200             }
201              
202             before _clear_labels => sub {
203             my $self = shift;
204             delete $self->raw_content->{labels};
205             };
206              
207             # We might already have all the label info, otherwise we can fetch all the
208             # labels at once rather iterating over each id, just like with comments.
209             sub _build_labels {
210 0     0     my $self = shift;
211              
212 0 0         if ( $self->raw_content->{labels} ) {
213             return [
214             map {
215 0           WebService::PivotalTracker::Label->new(
216             raw_content => $_,
217             pt_api => $self->_pt_api,
218             )
219 0           } @{ $self->raw_content->{labels} }
  0            
220             ];
221             }
222              
223 0           my $raw_labels = $self->_client->get( $self->_labels_uri );
224              
225             return [
226             map {
227 0           WebService::PivotalTracker::Label->new(
228             raw_content => $_,
229             pt_api => $self->_pt_api,
230             )
231 0           } @{$raw_labels}
  0            
232             ];
233             }
234              
235             sub _labels_uri {
236 0     0     my $self = shift;
237              
238 0           my $path = sprintf(
239             '/projects/%s/stories/%s/labels',
240             $self->project_id,
241             $self->id,
242             );
243              
244 0           return $self->_client->build_uri($path);
245             }
246              
247             sub _self_uri {
248 0     0     my $self = shift;
249              
250 0           return $self->_client->build_uri(
251             sprintf(
252             '/stories/%s',
253             $self->id,
254             )
255             );
256             }
257              
258             1;
259              
260             # ABSTRACT: A single story
261              
262             __END__
263              
264             =pod
265              
266             =encoding UTF-8
267              
268             =head1 NAME
269              
270             WebService::PivotalTracker::Story - A single story
271              
272             =head1 VERSION
273              
274             version 0.12
275              
276             =head1 SYNOPSIS
277              
278             =head1 DESCRIPTION
279              
280             This class represents a single story.
281              
282             =for Test::Synopsis my $project;
283              
284             my $iterations = $project->stories( ... );
285              
286             =head1 ATTRIBUTES
287              
288             This class provides the following attribute accessor methods. Each one
289             corresponds to a property defined by the L<PT REST API V5 story resource
290             docs|https://www.pivotaltracker.com/help/api/rest/v5#story_resource>.
291              
292             =head2 id
293              
294             =head2 project_id
295              
296             =head2 name
297              
298             =head2 description
299              
300             The description in Markdown.
301              
302             =head2 story_type
303              
304             =head2 current_state
305              
306             =head2 estimate
307              
308             =head2 accepted_at
309              
310             This will be returned as a L<DateTime> object.
311              
312             =head2 deadline
313              
314             This will be returned as a L<DateTime> object.
315              
316             =head2 requested_by_id
317              
318             =head2 owner_ids
319              
320             An array reference.
321              
322             =head2 task_ids
323              
324             An array reference.
325              
326             =head2 follower_ids
327              
328             An array reference.
329              
330             =head2 created_at
331              
332             This will be returned as a L<DateTime> object.
333              
334             =head2 updated_at
335              
336             This will be returned as a L<DateTime> object.
337              
338             =head2 url
339              
340             This will be returned as a L<URI> object.
341              
342             =head2 kind
343              
344             =head2 raw_content
345              
346             The raw JSON used to create this object.
347              
348             =head1 METHODS
349              
350             This class provides the following methods:
351              
352             =head2 $story->comments
353              
354             This method returns an array reference of
355             L<WebService::PivotalTracker::Comment> objects.
356              
357             =head2 $story->labels
358              
359             This method returns an array reference of L<WebService::PivotalTracker::Label>
360             objects.
361              
362             =head2 $story->requested_by
363              
364             This method returns a L<WebService::PivotalTracker::Person> representing the
365             person who is the requester for the story.
366              
367             =head2 $story->update( ... )
368              
369             This method will update the story's properties as specified.
370              
371             =head2 $story->add_comment( ... )
372              
373             This method adds a comment to a story. It accepts two arguments:
374              
375             =over 4
376              
377             =item * text
378              
379             The text of the comment in Markdown.
380              
381             This is required.
382              
383             =item * person_id
384              
385             By default, the comment will be attributed to whoever owns the token, but you
386             can use this to override that.
387              
388             =back
389              
390             =head2 $story->add_label( ... )
391              
392             This method accepts a single argument, C<name>, which is the name of the label
393             to add.
394              
395             =head1 SUPPORT
396              
397             Bugs may be submitted through L<https://github.com/maxmind/WebService-PivotalTracker/issues>.
398              
399             =head1 AUTHOR
400              
401             Dave Rolsky <autarch@urth.org>
402              
403             =head1 COPYRIGHT AND LICENSE
404              
405             This software is Copyright (c) 2016 - 2020 by MaxMind, Inc.
406              
407             This is free software, licensed under:
408              
409             The Artistic License 2.0 (GPL Compatible)
410              
411             =cut