]> git.donarmstrong.com Git - debbugs.git/blob - Debbugs/SOAP.pm
merge changes from don source branch
[debbugs.git] / Debbugs / SOAP.pm
1 # This module is part of debbugs, and is released
2 # under the terms of the GPL version 2, or any later version at your option.
3 # See the file README and COPYING for more information.
4 # Copyright 2007 by Don Armstrong <don@donarmstrong.com>.
5
6 package Debbugs::SOAP;
7
8 =head1 NAME
9
10 Debbugs::SOAP --
11
12 =head1 SYNOPSIS
13
14
15 =head1 DESCRIPTION
16
17
18 =head1 BUGS
19
20 None known.
21
22 =cut
23
24 use warnings;
25 use strict;
26 use vars qw($DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
27 use base qw(Exporter SOAP::Server::Parameters);
28
29 BEGIN{
30      $DEBUG = 0 unless defined $DEBUG;
31
32      @EXPORT = ();
33      %EXPORT_TAGS = (
34                     );
35      @EXPORT_OK = ();
36      Exporter::export_ok_tags();
37      $EXPORT_TAGS{all} = [@EXPORT_OK];
38
39 }
40
41
42 use IO::File;
43 use Debbugs::Status qw(get_bug_status);
44 use Debbugs::Common qw(make_list getbuglocation getbugcomponent);
45 use Storable qw(nstore retrieve);
46 use Scalar::Util qw(looks_like_number);
47
48
49 our $CURRENT_VERSION = 1;
50
51 =head2 get_usertag
52
53      my %ut = get_usertag('don@donarmstrong.com','this-bug-sucks','eat-this-bug');
54      my %ut = get_usertag('don@donarmstrong.com');
55
56 Returns a hashref of bugs which have the specified usertags for the
57 user set.
58
59 In the second case, returns all of the usertags for the user passed.
60
61 =cut
62
63 use Debbugs::User qw(read_usertags);
64
65 sub get_usertag {
66      my $VERSION = __populate_version(pop);
67      my ($self,$email, @tags) = @_;
68      my %ut = ();
69      read_usertags(\%ut, $email);
70      my %tags;
71      @tags{@tags} = (1) x @tags;
72      if (keys %tags > 0) {
73           for my $tag (keys %ut) {
74                delete $ut{$tag} unless exists $tags{$tag};
75           }
76      }
77      return \%ut;
78 }
79
80
81 use Debbugs::Status;
82
83 =head2 get_status 
84
85      my @statuses = get_status(@bugs);
86      my @statuses = get_status([bug => 304234,
87                                 dist => 'unstable',
88                                ],
89                                [bug => 304233,
90                                 dist => 'unstable',
91                                ],
92                               )
93
94 Returns an arrayref of hashrefs which output the status for specific
95 sets of bugs.
96
97 In the first case, no options are passed to
98 L<Debbugs::Status::get_bug_status> besides the bug number; in the
99 second the bug, dist, arch, bugusertags, sourceversions, and version
100 parameters are passed if they are present.
101
102 As a special case for suboptimal SOAP implementations, if only one
103 argument is passed to get_status and it is an arrayref which either is
104 empty, has a number as the first element, or contains an arrayref as
105 the first element, the outer arrayref is dereferenced, and processed
106 as in the examples above.
107
108 See L<Debbugs::Status::get_bug_status> for details.
109
110 =cut
111
112 sub get_status {
113      my $VERSION = __populate_version(pop);
114      my ($self,@bugs) = @_;
115
116      if (@bugs == 1 and
117          ref($bugs[0]) and
118          (@{$bugs[0]} == 0 or
119           ref($bugs[0][0]) or
120           looks_like_number($bugs[0][0])
121          )
122         ) {
123               @bugs = @{$bugs[0]};
124      }
125      my %status;
126      for my $bug (@bugs) {
127           my $bug_status;
128           if (ref($bug)) {
129                my %param = __collapse_params(@{$bug});
130                $bug_status = get_bug_status(map {(exists $param{$_})?($_,$param{$_}):()}
131                                             qw(bug dist arch bugusertags sourceversions version)
132                                            );
133           }
134           else {
135                $bug_status = get_bug_status(bug => $bug);
136           }
137           if (defined $bug_status and keys %{$bug_status} > 0) {
138                $status{$bug}  = $bug_status;
139           }
140      }
141 #     __prepare_response($self);
142      return \%status;
143 }
144
145 =head2 get_bugs
146
147      my @bugs = get_bugs(...);
148      my @bugs = get_bugs([...]);
149
150 Returns a list of bugs. In the second case, allows the variable
151 parameters to be specified as an array reference in case your favorite
152 language's SOAP implementation is craptacular.
153
154 See L<Debbugs::Bugs::get_bugs> for details on what C<...> actually
155 means.
156
157 =cut
158
159 use Debbugs::Bugs qw();
160
161 sub get_bugs{
162      my $VERSION = __populate_version(pop);
163      my ($self,@params) = @_;
164      # Because some soap implementations suck and can't handle
165      # variable numbers of arguments we allow get_bugs([]);
166      if (@params == 1 and ref($params[0]) eq 'ARRAY') {
167           @params = @{$params[0]};
168      }
169      my %params = __collapse_params(@params);
170      my @bugs;
171      @bugs = Debbugs::Bugs::get_bugs(%params);
172      return \@bugs;
173 }
174
175 =head2 newest_bugs
176
177      my @bugs = newest_bugs(5);
178
179 Returns a list of the newest bugs. [Note that all bugs are *not*
180 guaranteed to exist, but they should in the most common cases.]
181
182 =cut
183
184 sub newest_bugs{
185      my $VERSION = __populate_version(pop);
186      my ($self,$num) = @_;
187      my $newest_bug = Debbugs::Bugs::newest_bug();
188      return [($newest_bug - $num + 1) .. $newest_bug];
189
190 }
191
192 =head2 get_bug_log
193
194      my $bug_log = get_bug_log($bug);
195      my $bug_log = get_bug_log($bug,$msg_num);
196
197 Retuns a parsed set of the bug log; this is an array of hashes with
198 the following
199
200  [{html => '',
201    header => '',
202    body    => '',
203    attachments => [],
204    msg_num     => 5,
205   },
206   {html => '',
207    header => '',
208    body    => '',
209    attachments => [],
210   },
211  ]
212
213
214 Currently $msg_num is completely ignored.
215
216 =cut
217
218 use Debbugs::Log qw();
219 use Debbugs::MIME qw(parse);
220
221 sub get_bug_log{
222      my $VERSION = __populate_version(pop);
223      my ($self,$bug,$msg_num) = @_;
224
225      my $location = getbuglocation($bug,'log');
226      my $bug_log = getbugcomponent($bug,'log',$location);
227
228      my $log_fh = IO::File->new($bug_log, 'r') or
229           die "Unable to open bug log $bug_log for reading: $!";
230
231      my $log = Debbugs::Log->new($log_fh) or
232           die "Debbugs::Log was unable to be initialized";
233
234      my %seen_msg_ids;
235      my $current_msg=0;
236      my $status = {};
237      my @messages;
238      while (my $record = $log->read_record()) {
239           $current_msg++;
240           #next if defined $msg_num and ($current_msg ne $msg_num);
241           next unless $record->{type} eq 'incoming-recv';
242           my ($msg_id) = $record->{text} =~ /^Message-Id:\s+<(.+)>/im;
243           next if defined $msg_id and exists $seen_msg_ids{$msg_id};
244           $seen_msg_ids{$msg_id} = 1 if defined $msg_id;
245           next if defined $msg_id and $msg_id =~ /handler\..+\.ack(?:info)?\@/;
246           my $message = parse($record->{text});
247           my ($header,$body) = map {join("\n",make_list($_))}
248                @{$message}{qw(header body)};
249           push @messages,{header => $header,
250                           body   => $body,
251                           attachments => [],
252                           msg_num => $current_msg,
253                          };
254      }
255      return \@messages;
256 }
257
258
259 =head1 VERSION COMPATIBILITY
260
261 The functionality provided by the SOAP interface will change over time.
262
263 To the greatest extent possible, we will attempt to provide backwards
264 compatibility with previous versions; however, in order to have
265 backwards compatibility, you need to specify the version with which
266 you are compatible.
267
268 =cut
269
270 sub __populate_version{
271      my ($request) = @_;
272      return $request->{___debbugs_soap_version};
273 }
274
275 sub __collapse_params{
276      my @params = @_;
277
278      my %params;
279      # Because some clients can't handle passing arrayrefs, we allow
280      # options to be specified multiple times
281      while (my ($key,$value) = splice @params,0,2) {
282           push @{$params{$key}}, make_list($value);
283      }
284      # However, for singly specified options, we want to pull them
285      # back out
286      for my $key (keys %params) {
287           if (@{$params{$key}} == 1) {
288                ($params{$key}) = @{$params{$key}}
289           }
290      }
291      return %params;
292 }
293
294
295 1;
296
297
298 __END__
299
300
301
302
303
304