line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package BusyBird::Main::PSGI; |
2
|
5
|
|
|
5
|
|
4722
|
use strict; |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
175
|
|
3
|
5
|
|
|
5
|
|
26
|
use warnings; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
156
|
|
4
|
5
|
|
|
5
|
|
21
|
use BusyBird::Util qw(set_param future_of); |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
260
|
|
5
|
5
|
|
|
5
|
|
2016
|
use BusyBird::Main::PSGI::View; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
180
|
|
6
|
5
|
|
|
5
|
|
2436
|
use Router::Simple; |
|
5
|
|
|
|
|
13374
|
|
|
5
|
|
|
|
|
130
|
|
7
|
5
|
|
|
5
|
|
2273
|
use Plack::Request; |
|
5
|
|
|
|
|
181498
|
|
|
5
|
|
|
|
|
162
|
|
8
|
5
|
|
|
5
|
|
2367
|
use Plack::Builder (); |
|
5
|
|
|
|
|
23845
|
|
|
5
|
|
|
|
|
107
|
|
9
|
5
|
|
|
5
|
|
2051
|
use Plack::App::File; |
|
5
|
|
|
|
|
28091
|
|
|
5
|
|
|
|
|
152
|
|
10
|
5
|
|
|
5
|
|
32
|
use Try::Tiny; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
299
|
|
11
|
5
|
|
|
5
|
|
21
|
use JSON qw(decode_json); |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
38
|
|
12
|
5
|
|
|
5
|
|
643
|
use Scalar::Util qw(looks_like_number); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
206
|
|
13
|
5
|
|
|
5
|
|
21
|
use List::Util qw(min); |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
260
|
|
14
|
5
|
|
|
5
|
|
20
|
use Carp; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
282
|
|
15
|
5
|
|
|
5
|
|
39
|
use Exporter qw(import); |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
152
|
|
16
|
5
|
|
|
5
|
|
18
|
use URI::Escape qw(uri_unescape); |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
197
|
|
17
|
5
|
|
|
5
|
|
21
|
use Encode qw(decode_utf8); |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
334
|
|
18
|
5
|
|
|
5
|
|
33
|
use Future::Q; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
121
|
|
19
|
5
|
|
|
5
|
|
19
|
use POSIX qw(ceil); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
76
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our @EXPORT_OK = qw(create_psgi_app); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub create_psgi_app { |
25
|
45
|
|
|
45
|
1
|
1030
|
my ($main_obj) = @_; |
26
|
45
|
|
|
|
|
263
|
my $self = __PACKAGE__->_new(main_obj => $main_obj); |
27
|
45
|
|
|
|
|
161
|
return $self->_to_app; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub _new { |
31
|
45
|
|
|
45
|
|
157
|
my ($class, %params) = @_; |
32
|
45
|
|
|
|
|
347
|
my $self = bless { |
33
|
|
|
|
|
|
|
router => Router::Simple->new, |
34
|
|
|
|
|
|
|
view => undef, ## lazy build |
35
|
|
|
|
|
|
|
}, $class; |
36
|
45
|
|
|
|
|
480
|
$self->set_param(\%params, "main_obj", undef, 1); |
37
|
45
|
|
|
|
|
159
|
$self->_build_routes(); |
38
|
45
|
|
|
|
|
1929
|
return $self; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub _to_app { |
42
|
45
|
|
|
45
|
|
86
|
my $self = shift; |
43
|
45
|
|
|
|
|
177
|
my $sharedir = $self->{main_obj}->get_config("sharedir_path"); |
44
|
45
|
|
|
|
|
235
|
$sharedir =~ s{/+$}{}; |
45
|
|
|
|
|
|
|
return Plack::Builder::builder { |
46
|
45
|
|
|
45
|
|
1843
|
Plack::Builder::enable 'ContentLength'; |
47
|
45
|
|
|
|
|
6377
|
Plack::Builder::mount '/static' => Plack::App::File->new( |
48
|
|
|
|
|
|
|
root => File::Spec->catdir($sharedir, 'www', 'static') |
49
|
|
|
|
|
|
|
)->to_app; |
50
|
45
|
|
|
|
|
2821
|
Plack::Builder::mount '/' => $self->_my_app; |
51
|
45
|
|
|
|
|
383
|
}; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub _my_app { |
55
|
45
|
|
|
45
|
|
67
|
my ($self) = @_; |
56
|
|
|
|
|
|
|
return sub { |
57
|
185
|
|
|
185
|
|
839037
|
my ($env) = @_; |
58
|
185
|
|
66
|
|
|
1065
|
$self->{view} ||= BusyBird::Main::PSGI::View->new(main_obj => $self->{main_obj}, script_name => $env->{SCRIPT_NAME}); |
59
|
185
|
100
|
|
|
|
822
|
if(my $dest = $self->{router}->match($env)) { |
60
|
179
|
|
|
|
|
14493
|
my $req = Plack::Request->new($env); |
61
|
179
|
|
|
|
|
1417
|
my $code = $dest->{code}; |
62
|
179
|
|
|
|
|
317
|
my $method = $dest->{method}; |
63
|
179
|
50
|
|
|
|
786
|
return defined($code) ? $code->($self, $req, $dest) : $self->$method($req, $dest); |
64
|
|
|
|
|
|
|
}else { |
65
|
6
|
|
|
|
|
578
|
return $self->{view}->response_notfound(); |
66
|
|
|
|
|
|
|
} |
67
|
45
|
|
|
|
|
254
|
}; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub _build_routes { |
71
|
45
|
|
|
45
|
|
56
|
my ($self) = @_; |
72
|
45
|
|
|
|
|
192
|
my $tl_mapper = $self->{router}->submapper( |
73
|
|
|
|
|
|
|
'/timelines/{timeline}', {} |
74
|
|
|
|
|
|
|
); |
75
|
45
|
|
|
|
|
1226
|
$tl_mapper->connect('/statuses.{format}', |
76
|
|
|
|
|
|
|
{method => '_handle_tl_get_statuses'}, {method => 'GET'}); |
77
|
45
|
|
|
|
|
5527
|
$tl_mapper->connect('/statuses.json', |
78
|
|
|
|
|
|
|
{method => '_handle_tl_post_statuses'}, {method => 'POST'}); |
79
|
45
|
|
|
|
|
3700
|
$tl_mapper->connect('/ack.json', |
80
|
|
|
|
|
|
|
{method => '_handle_tl_ack'}, {method => 'POST'}); |
81
|
45
|
|
|
|
|
3189
|
$tl_mapper->connect('/updates/unacked_counts.json', |
82
|
|
|
|
|
|
|
{method => '_handle_tl_get_unacked_counts'}, {method => 'GET'}); |
83
|
45
|
|
|
|
|
3567
|
$tl_mapper->connect($_, {method => '_handle_tl_index'}) foreach "", qw(/ /index.html /index.htm); |
84
|
45
|
|
|
|
|
10933
|
$self->{router}->connect('/updates/unacked_counts.json', |
85
|
|
|
|
|
|
|
{method => '_handle_get_unacked_counts'}, {method => 'GET'}); |
86
|
45
|
|
|
|
|
2008
|
foreach my $path ("/", "/index.html") { |
87
|
90
|
|
|
|
|
2207
|
$self->{router}->connect($path, {method => '_handle_get_timeline_list'}, {method => 'GET'}); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub _get_timeline_name { |
92
|
152
|
|
|
152
|
|
261
|
my ($dest) = @_; |
93
|
152
|
|
|
|
|
235
|
my $name = $dest->{timeline}; |
94
|
152
|
50
|
|
|
|
340
|
$name = "" if not defined($name); |
95
|
152
|
|
|
|
|
278
|
$name =~ s/\+/ /g; |
96
|
152
|
|
|
|
|
368
|
return decode_utf8(uri_unescape($name)); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub _get_timeline { |
100
|
135
|
|
|
135
|
|
201
|
my ($self, $dest) = @_; |
101
|
135
|
|
|
|
|
284
|
my $name = _get_timeline_name($dest); |
102
|
135
|
|
|
|
|
3947
|
my $timeline = $self->{main_obj}->get_timeline($name); |
103
|
135
|
100
|
|
|
|
1220
|
if(!defined($timeline)) { |
104
|
4
|
|
|
|
|
35
|
die qq{No timeline named $name}; |
105
|
|
|
|
|
|
|
} |
106
|
131
|
|
|
|
|
249
|
return $timeline; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _handle_tl_get_statuses { |
110
|
70
|
|
|
70
|
|
137
|
my ($self, $req, $dest) = @_; |
111
|
|
|
|
|
|
|
return sub { |
112
|
70
|
|
|
70
|
|
3378
|
my $responder = shift; |
113
|
70
|
|
|
|
|
91
|
my $timeline; |
114
|
70
|
|
|
|
|
234
|
my $only_statuses = !!($req->query_parameters->{only_statuses}); |
115
|
70
|
100
|
100
|
|
|
5960
|
my $format = !defined($dest->{format}) ? "" |
|
|
50
|
|
|
|
|
|
116
|
|
|
|
|
|
|
: (lc($dest->{format}) eq "json" && $only_statuses) ? "json_only_statuses" |
117
|
|
|
|
|
|
|
: $dest->{format}; |
118
|
|
|
|
|
|
|
Future::Q->try(sub { |
119
|
70
|
|
|
|
|
2534
|
$timeline = $self->_get_timeline($dest); |
120
|
69
|
|
100
|
|
|
173
|
my $count = $req->query_parameters->{count} || 20; |
121
|
69
|
50
|
33
|
|
|
865
|
if(!looks_like_number($count) || int($count) != $count) { |
122
|
0
|
|
|
|
|
0
|
die "count parameter must be an integer\n"; |
123
|
|
|
|
|
|
|
} |
124
|
69
|
|
100
|
|
|
159
|
my $ack_state = $req->query_parameters->{ack_state} || 'any'; |
125
|
69
|
|
|
|
|
493
|
my $max_id = decode_utf8($req->query_parameters->{max_id}); |
126
|
69
|
|
|
|
|
799
|
return future_of($timeline, "get_statuses", |
127
|
|
|
|
|
|
|
count => $count, ack_state => $ack_state, max_id => $max_id); |
128
|
|
|
|
|
|
|
})->then(sub { |
129
|
65
|
|
|
|
|
11179
|
my $statuses = shift; |
130
|
65
|
|
|
|
|
325
|
$responder->($self->{view}->response_statuses( |
131
|
|
|
|
|
|
|
statuses => $statuses, http_code => 200, format => $format, |
132
|
|
|
|
|
|
|
timeline_name => $timeline->name |
133
|
|
|
|
|
|
|
)); |
134
|
|
|
|
|
|
|
})->catch(sub { |
135
|
5
|
|
|
|
|
1584
|
my ($error, $is_normal_error) = @_; |
136
|
5
|
100
|
|
|
|
40
|
$responder->($self->{view}->response_statuses( |
|
|
100
|
|
|
|
|
|
137
|
|
|
|
|
|
|
error => "$error", http_code => ($is_normal_error ? 500 : 400), format => $format, |
138
|
|
|
|
|
|
|
($timeline ? (timeline_name => $timeline->name) : ()) |
139
|
|
|
|
|
|
|
)); |
140
|
70
|
|
|
|
|
558
|
}); |
141
|
70
|
|
|
|
|
670
|
}; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub _handle_tl_post_statuses { |
145
|
31
|
|
|
31
|
|
63
|
my ($self, $req, $dest) = @_; |
146
|
|
|
|
|
|
|
return sub { |
147
|
31
|
|
|
31
|
|
1632
|
my $responder = shift; |
148
|
|
|
|
|
|
|
Future::Q->try(sub { |
149
|
31
|
|
|
|
|
1216
|
my $timeline = $self->_get_timeline($dest); |
150
|
30
|
|
|
|
|
137
|
my $posted_obj = decode_json($req->content); |
151
|
29
|
100
|
|
|
|
26065
|
if(ref($posted_obj) ne 'ARRAY') { |
152
|
5
|
|
|
|
|
11
|
$posted_obj = [$posted_obj]; |
153
|
|
|
|
|
|
|
} |
154
|
29
|
|
|
|
|
121
|
return future_of($timeline, "add_statuses", statuses => $posted_obj); |
155
|
|
|
|
|
|
|
})->then(sub { |
156
|
27
|
|
|
|
|
5475
|
my $added_num = shift; |
157
|
27
|
|
|
|
|
247
|
$responder->($self->{view}->response_json(200, {count => $added_num + 0})); |
158
|
|
|
|
|
|
|
})->catch(sub { |
159
|
4
|
|
|
|
|
1400
|
my ($e, $is_normal_error) = @_; |
160
|
4
|
100
|
|
|
|
30
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
161
|
31
|
|
|
|
|
314
|
}); |
162
|
31
|
|
|
|
|
342
|
}; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _handle_tl_ack { |
166
|
28
|
|
|
28
|
|
58
|
my ($self, $req, $dest) = @_; |
167
|
|
|
|
|
|
|
return sub { |
168
|
28
|
|
|
28
|
|
1364
|
my $responder = shift; |
169
|
|
|
|
|
|
|
Future::Q->try(sub { |
170
|
28
|
|
|
|
|
1027
|
my $timeline = $self->_get_timeline($dest); |
171
|
27
|
|
|
|
|
43
|
my $max_id = undef; |
172
|
27
|
|
|
|
|
42
|
my $ids = undef; |
173
|
27
|
100
|
|
|
|
115
|
if($req->content) { |
174
|
23
|
|
|
|
|
18927
|
my $body_obj = decode_json($req->content); |
175
|
23
|
50
|
|
|
|
564
|
if(ref($body_obj) ne 'HASH') { |
176
|
0
|
|
|
|
|
0
|
die "Response body must be an object.\n"; |
177
|
|
|
|
|
|
|
} |
178
|
23
|
|
|
|
|
66
|
$max_id = $body_obj->{max_id}; |
179
|
23
|
|
|
|
|
47
|
$ids = $body_obj->{ids}; |
180
|
|
|
|
|
|
|
} |
181
|
27
|
|
|
|
|
390
|
return future_of($timeline, "ack_statuses", max_id => $max_id, ids => $ids); |
182
|
|
|
|
|
|
|
})->then(sub { |
183
|
25
|
|
|
|
|
3713
|
my $acked_num = shift; |
184
|
25
|
|
|
|
|
166
|
$responder->($self->{view}->response_json(200, {count => $acked_num + 0})); |
185
|
|
|
|
|
|
|
})->catch(sub { |
186
|
3
|
|
|
|
|
962
|
my ($e, $is_normal_error) = @_; |
187
|
3
|
100
|
|
|
|
29
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
188
|
28
|
|
|
|
|
233
|
}); |
189
|
28
|
|
|
|
|
297
|
}; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _handle_tl_get_unacked_counts { |
193
|
6
|
|
|
6
|
|
10
|
my ($self, $req, $dest) = @_; |
194
|
|
|
|
|
|
|
return sub { |
195
|
6
|
|
|
6
|
|
279
|
my $responder = shift; |
196
|
|
|
|
|
|
|
Future::Q->try(sub { |
197
|
6
|
|
|
|
|
361
|
my $timeline = $self->_get_timeline($dest); |
198
|
5
|
|
|
|
|
17
|
my $query_params = $req->query_parameters; |
199
|
5
|
|
|
|
|
365
|
my %assumed = (); |
200
|
5
|
100
|
|
|
|
17
|
if(defined $query_params->{total}) { |
201
|
3
|
|
|
|
|
9
|
$assumed{total} = delete $query_params->{total}; |
202
|
|
|
|
|
|
|
} |
203
|
5
|
|
|
|
|
16
|
foreach my $query_key (keys %$query_params) { |
204
|
5
|
50
|
|
|
|
19
|
next if !looks_like_number($query_key); |
205
|
5
|
50
|
|
|
|
14
|
next if int($query_key) != $query_key; |
206
|
5
|
|
|
|
|
10
|
$assumed{$query_key} = $query_params->{$query_key}; |
207
|
|
|
|
|
|
|
} |
208
|
5
|
|
|
|
|
20
|
my $ret_future = Future::Q->new; |
209
|
|
|
|
|
|
|
$timeline->watch_unacked_counts(assumed => \%assumed, callback => sub { |
210
|
5
|
|
|
|
|
8
|
my ($error, $w, $unacked_counts) = @_; |
211
|
5
|
|
|
|
|
18
|
$w->cancel(); ## immediately cancel the watcher to prevent multiple callbacks |
212
|
5
|
50
|
|
|
|
52
|
if($error) { |
213
|
0
|
|
|
|
|
0
|
$ret_future->reject($error, 1); |
214
|
|
|
|
|
|
|
}else { |
215
|
5
|
|
|
|
|
16
|
$ret_future->fulfill($unacked_counts); |
216
|
|
|
|
|
|
|
} |
217
|
5
|
|
|
|
|
88
|
}); |
218
|
5
|
|
|
|
|
26
|
return $ret_future; |
219
|
|
|
|
|
|
|
})->then(sub { |
220
|
5
|
|
|
|
|
566
|
my ($unacked_counts) = @_; |
221
|
5
|
|
|
|
|
23
|
$responder->($self->{view}->response_json(200, {unacked_counts => $unacked_counts})); |
222
|
|
|
|
|
|
|
})->catch(sub { |
223
|
1
|
|
|
|
|
255
|
my ($e, $is_normal_error) = @_; |
224
|
1
|
50
|
|
|
|
8
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
225
|
6
|
|
|
|
|
40
|
}); |
226
|
6
|
|
|
|
|
51
|
}; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _handle_get_unacked_counts { |
230
|
17
|
|
|
17
|
|
29
|
my ($self, $req, $dest) = @_; |
231
|
|
|
|
|
|
|
return sub { |
232
|
17
|
|
|
17
|
|
803
|
my $responder = shift; |
233
|
|
|
|
|
|
|
Future::Q->try(sub { |
234
|
17
|
|
|
|
|
594
|
my $query_params = $req->query_parameters; |
235
|
17
|
|
|
|
|
1950
|
my $level = $query_params->{level}; |
236
|
17
|
100
|
33
|
|
|
112
|
if(not defined($level)) { |
|
|
50
|
66
|
|
|
|
|
237
|
3
|
|
|
|
|
6
|
$level = "total"; |
238
|
|
|
|
|
|
|
}elsif($level ne 'total' && (!looks_like_number($level) || int($level) != $level)) { |
239
|
0
|
|
|
|
|
0
|
die "level parameter must be an integer\n"; |
240
|
|
|
|
|
|
|
} |
241
|
17
|
|
|
|
|
26
|
my %assumed = (); |
242
|
17
|
|
|
|
|
54
|
foreach my $query_key (keys %$query_params) { |
243
|
62
|
100
|
|
|
|
609
|
next if substr($query_key, 0, 3) ne 'tl_'; |
244
|
46
|
|
|
|
|
116
|
$assumed{decode_utf8(substr($query_key, 3))} = $query_params->{$query_key}; |
245
|
|
|
|
|
|
|
} |
246
|
17
|
|
|
|
|
207
|
my $ret_future = Future::Q->new; |
247
|
|
|
|
|
|
|
$self->{main_obj}->watch_unacked_counts( |
248
|
|
|
|
|
|
|
level => $level, assumed => \%assumed, callback => sub { |
249
|
15
|
|
|
|
|
18
|
my ($error, $w, $tl_unacked_counts) = @_; |
250
|
15
|
|
|
|
|
41
|
$w->cancel(); ## immediately cancel the watcher to prevent multiple callbacks |
251
|
15
|
50
|
|
|
|
361
|
if($error) { |
252
|
0
|
|
|
|
|
0
|
$ret_future->reject($error, 1); |
253
|
|
|
|
|
|
|
}else { |
254
|
15
|
|
|
|
|
43
|
$ret_future->fulfill($tl_unacked_counts); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
17
|
|
|
|
|
331
|
); |
258
|
15
|
|
|
|
|
81
|
return $ret_future; |
259
|
|
|
|
|
|
|
})->then(sub { |
260
|
15
|
|
|
|
|
1850
|
my ($tl_unacked_counts) = @_; |
261
|
15
|
|
|
|
|
66
|
$responder->($self->{view}->response_json(200, {unacked_counts => $tl_unacked_counts})); |
262
|
|
|
|
|
|
|
})->catch(sub { |
263
|
2
|
|
|
|
|
906
|
my ($e, $is_normal_error) = @_; |
264
|
2
|
50
|
|
|
|
16
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
265
|
17
|
|
|
|
|
141
|
}); |
266
|
17
|
|
|
|
|
151
|
}; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub _handle_tl_index { |
270
|
17
|
|
|
17
|
|
26
|
my ($self, $req, $dest) = @_; |
271
|
17
|
|
|
|
|
48
|
return $self->{view}->response_timeline(_get_timeline_name($dest)); |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub _handle_get_timeline_list { |
275
|
10
|
|
|
10
|
|
16
|
my ($self, $req, $dest) = @_; |
276
|
|
|
|
|
|
|
return sub { |
277
|
10
|
|
|
10
|
|
529
|
my $responder = shift; |
278
|
|
|
|
|
|
|
Future::Q->try(sub { |
279
|
10
|
|
|
|
|
378
|
my $num_per_page = $self->{main_obj}->get_config('timeline_list_per_page'); |
280
|
112
|
|
|
|
|
994
|
my @timelines = grep { |
281
|
10
|
|
|
|
|
45
|
!$self->{main_obj}->get_timeline_config($_->name, "hidden") |
282
|
|
|
|
|
|
|
} $self->{main_obj}->get_all_timelines(); |
283
|
10
|
50
|
|
|
|
58
|
if(@timelines == 0) { |
284
|
0
|
|
|
|
|
0
|
die "No visible timeline. Probably you must configure config.psgi to create a timeline."; |
285
|
|
|
|
|
|
|
} |
286
|
10
|
|
|
|
|
56
|
my $page_num = ceil(scalar(@timelines) / $num_per_page); |
287
|
10
|
|
|
|
|
16
|
my $cur_page = 0; |
288
|
10
|
|
|
|
|
34
|
my $query = $req->query_parameters; |
289
|
10
|
100
|
|
|
|
640
|
if(defined $query->{page}) { |
290
|
7
|
100
|
100
|
|
|
72
|
if(!looks_like_number($query->{page}) || $query->{page} < 0 || $query->{page} >= $page_num) { |
|
|
|
100
|
|
|
|
|
291
|
4
|
|
|
|
|
22
|
die "Invalid page parameter\n"; |
292
|
|
|
|
|
|
|
} |
293
|
3
|
|
|
|
|
8
|
$cur_page = $query->{page}; |
294
|
|
|
|
|
|
|
} |
295
|
6
|
|
|
|
|
72
|
my @target_timelines = @timelines[($cur_page * $num_per_page) .. min(($cur_page+1) * $num_per_page - 1, $#timelines)]; |
296
|
24
|
|
|
|
|
447
|
return Future::Q->needs_all(map { future_of($_, "get_unacked_counts") } @target_timelines)->then(sub { |
297
|
6
|
|
|
|
|
1622
|
my (@unacked_counts_list) = @_; |
298
|
24
|
|
|
|
|
42
|
my @timeline_unacked_counts = map { |
299
|
6
|
|
|
|
|
19
|
+{ name => $target_timelines[$_]->name, counts => $unacked_counts_list[$_] } |
300
|
|
|
|
|
|
|
} 0 .. $#target_timelines; |
301
|
6
|
|
|
|
|
67
|
$responder->( $self->{view}->response_timeline_list( |
302
|
|
|
|
|
|
|
timeline_unacked_counts => \@timeline_unacked_counts, |
303
|
|
|
|
|
|
|
total_page_num => $page_num, |
304
|
|
|
|
|
|
|
cur_page => $cur_page |
305
|
|
|
|
|
|
|
) ); |
306
|
6
|
|
|
|
|
12
|
}); |
307
|
|
|
|
|
|
|
})->catch(sub { |
308
|
4
|
|
|
|
|
576
|
my ($error, $is_normal_error) = @_; |
309
|
4
|
50
|
|
|
|
18
|
$responder->($self->{view}->response_error_html( |
310
|
|
|
|
|
|
|
($is_normal_error ? 500 : 400), $error |
311
|
|
|
|
|
|
|
)); |
312
|
10
|
|
|
|
|
99
|
}); |
313
|
10
|
|
|
|
|
89
|
}; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
1; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
__END__ |