File: | C4/Message.pm |
Coverage: | 14.3% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package C4::Message; | |||||
2 | 14 14 14 | 475 71 879 | use strict; | |||
3 | 14 14 14 | 133 56 622 | use warnings; | |||
4 | 14 14 14 | 326 62 236 | use C4::Context; | |||
5 | 14 14 14 | 229 71 2346 | use C4::Letters; | |||
6 | 14 14 14 | 165 34 1115 | use YAML::Syck; | |||
7 | 14 14 14 | 119 64 20687 | use Carp; | |||
8 | ||||||
9 - 48 | =head1 NAME C4::Message - object for messages in the message_queue table =head1 SYNOPSIS How to add a new message to the queue: use C4::Message; use C4::Items; my $borrower = { borrowernumber => 1 }; my $item = C4::Items::GetItem(1); my $letter = C4::Letters::GetPreparedLetter ( module => 'circulation', letter_code => 'CHECKOUT', branchcode => $branch, tables => { 'biblio', $item->{biblionumber}, 'biblioitems', $item->{biblionumber}, }, ); C4::Message->enqueue($letter, $borrower->{borrowernumber}, 'email'); How to update a borrower's last checkout message: use C4::Message; my $borrower = { borrowernumber => 1 }; my $message = C4::Message->find_last_message($borrower, 'CHECKOUT', 'email'); $message->append("you also checked out some other book...."); $message->update; =head1 DESCRIPTION This module presents an OO interface to the message_queue. Previously, you could only add messages to the message_queue via C<C4::Letters::EnqueueMessage()>. With this module, you can also get previously inserted messages, manipulate them, and save them back to the database. =cut | |||||
49 | ||||||
50 | ||||||
51 | our $AUTOLOAD; | |||||
52 | ||||||
53 | ||||||
54 - 60 | =head2 Class Methods =head3 C4::Message->new(\%attributes) This method creates an in-memory version of a message object. =cut | |||||
61 | ||||||
62 | # C4::Message->new(\%attributes) -- constructor | |||||
63 | sub new { | |||||
64 | 0 | my ($class, $opts) = @_; | ||||
65 | 0 | $opts ||= {}; | ||||
66 | 0 | bless {%$opts} => $class; | ||||
67 | } | |||||
68 | ||||||
69 | ||||||
70 - 75 | =head3 C4::Message->find($id) This method searches the message_queue table for a row with the given C<message_id> and it'll return a C4::Message object if it finds one. =cut | |||||
76 | ||||||
77 | # C4::Message->find($id) -- find a message by its message_id | |||||
78 | sub find { | |||||
79 | 0 | my ($class, $id) = @_; | ||||
80 | 0 | my $dbh = C4::Context->dbh; | ||||
81 | 0 | my $msgs = $dbh->selectall_arrayref( | ||||
82 | qq{SELECT * FROM message_queue WHERE message_id = ?}, | |||||
83 | { Slice => {} }, | |||||
84 | $id, | |||||
85 | ); | |||||
86 | 0 | if (@$msgs) { | ||||
87 | 0 | return $class->new($msgs->[0]); | ||||
88 | } else { | |||||
89 | 0 | return undef; | ||||
90 | } | |||||
91 | } | |||||
92 | ||||||
93 - 99 | =head3 C4::Message->find_last_message($borrower, $letter_code, $transport) This method is used to get the borrower's most recent, pending, check-in or checkout message. (This makes it possible to add more information to the message before it gets sent out.) =cut | |||||
100 | ||||||
101 | # C4::Message->find_last_message($borrower, $letter_code, $transport) | |||||
102 | # -- get the borrower's most recent pending checkin or checkout notification | |||||
103 | sub find_last_message { | |||||
104 | 0 | my ($class, $borrower, $letter_code, $transport) = @_; | ||||
105 | # $type is the message_transport_type | |||||
106 | 0 | $transport ||= 'email'; | ||||
107 | 0 | my $dbh = C4::Context->dbh; | ||||
108 | 0 | my $msgs = $dbh->selectall_arrayref( | ||||
109 | qq{ | |||||
110 | SELECT * | |||||
111 | FROM message_queue | |||||
112 | WHERE status = 'pending' | |||||
113 | AND borrowernumber = ? | |||||
114 | AND letter_code = ? | |||||
115 | AND message_transport_type = ? | |||||
116 | }, | |||||
117 | { Slice => {} }, | |||||
118 | $borrower->{borrowernumber}, | |||||
119 | $letter_code, | |||||
120 | $transport, | |||||
121 | ); | |||||
122 | 0 | if (@$msgs) { | ||||
123 | 0 | return $class->new($msgs->[0]); | ||||
124 | } else { | |||||
125 | 0 | return undef; | ||||
126 | } | |||||
127 | } | |||||
128 | ||||||
129 | ||||||
130 - 135 | =head3 C4::Message->enqueue($letter, $borrower, $transport) This is a front-end for C<C4::Letters::EnqueueLetter()> that adds metadata to the message. =cut | |||||
136 | ||||||
137 | # C4::Message->enqueue($letter, $borrower, $transport) | |||||
138 | sub enqueue { | |||||
139 | 0 | my ($class, $letter, $borrower, $transport) = @_; | ||||
140 | 0 | my $metadata = _metadata($letter); | ||||
141 | 0 | my $to_address = _to_address($borrower, $transport); | ||||
142 | 0 | $letter->{metadata} = Dump($metadata); | ||||
143 | #carp "enqueuing... to $to_address"; | |||||
144 | 0 | C4::Letters::EnqueueLetter({ | ||||
145 | letter => $letter, | |||||
146 | borrowernumber => $borrower->{borrowernumber}, | |||||
147 | message_transport_type => $transport, | |||||
148 | to_address => $to_address, | |||||
149 | }); | |||||
150 | } | |||||
151 | ||||||
152 | # based on message $transport, pick an appropriate address to send to | |||||
153 | sub _to_address { | |||||
154 | 0 | my ($borrower, $transport) = @_; | ||||
155 | 0 | my $address; | ||||
156 | 0 | if ($transport eq 'email') { | ||||
157 | 0 | $address = $borrower->{email} | ||||
158 | || $borrower->{emailpro} | |||||
159 | || $borrower->{B_email}; | |||||
160 | } elsif ($transport eq 'sms') { | |||||
161 | 0 | $address = $borrower->{smsalertnumber} | ||||
162 | || $borrower->{phone} | |||||
163 | || $borrower->{phonepro} | |||||
164 | || $borrower->{B_phone}; | |||||
165 | } else { | |||||
166 | 0 | warn "'$transport' is an unknown message transport."; | ||||
167 | } | |||||
168 | 0 | if (not defined $address) { | ||||
169 | 0 | warn "An appropriate $transport address " | ||||
170 | . "for borrower $borrower->{userid} " | |||||
171 | . "could not be found."; | |||||
172 | } | |||||
173 | 0 | return $address; | ||||
174 | } | |||||
175 | ||||||
176 | # _metadata($letter) -- return the letter split into head/body/footer | |||||
177 | sub _metadata { | |||||
178 | 0 | my ($letter) = @_; | ||||
179 | 0 | if ($letter->{content} =~ /----/) { | ||||
180 | 0 | my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content}); | ||||
181 | return { | |||||
182 | 0 | header => $header, | ||||
183 | body => [$body], | |||||
184 | footer => $footer, | |||||
185 | }; | |||||
186 | } else { | |||||
187 | return { | |||||
188 | 0 | header => '', | ||||
189 | body => [$letter->{content}], | |||||
190 | footer => '', | |||||
191 | }; | |||||
192 | } | |||||
193 | } | |||||
194 | ||||||
195 - 202 | =head2 Instance Methods =head3 $message->update() This saves the $message object back to the database. It needs to have already been created via C<enqueue> for this to work. =cut | |||||
203 | ||||||
204 | # $object->update -- save object to database | |||||
205 | sub update { | |||||
206 | 0 | my ($self) = @_; | ||||
207 | 0 | my $dbh = C4::Context->dbh; | ||||
208 | 0 | $dbh->do( | ||||
209 | qq{ | |||||
210 | UPDATE message_queue | |||||
211 | SET | |||||
212 | borrowernumber = ?, | |||||
213 | subject = ?, | |||||
214 | content = ?, | |||||
215 | metadata = ?, | |||||
216 | letter_code = ?, | |||||
217 | message_transport_type = ?, | |||||
218 | status = ?, | |||||
219 | time_queued = ?, | |||||
220 | to_address = ?, | |||||
221 | from_address = ?, | |||||
222 | content_type = ? | |||||
223 | WHERE message_id = ? | |||||
224 | }, | |||||
225 | {}, | |||||
226 | $self->borrowernumber, | |||||
227 | $self->subject, | |||||
228 | $self->content, | |||||
229 | $self->{metadata}, # we want the raw YAML here | |||||
230 | $self->letter_code, | |||||
231 | $self->message_transport_type, | |||||
232 | $self->status, | |||||
233 | $self->time_queued, | |||||
234 | $self->to_address, | |||||
235 | $self->from_address, | |||||
236 | $self->content_type, | |||||
237 | $self->message_id | |||||
238 | ); | |||||
239 | } | |||||
240 | ||||||
241 - 246 | =head3 $message->metadata(\%new_metadata) This method automatically serializes and deserializes the metadata attribute. (It is stored in YAML format.) =cut | |||||
247 | ||||||
248 | # $object->metadata -- this is a YAML serialized column that contains a | |||||
249 | # structured representation of $object->content | |||||
250 | sub metadata { | |||||
251 | 0 | my ($self, $data) = @_; | ||||
252 | 0 | if ($data) { | ||||
253 | 0 | $data->{header} ||= ''; | ||||
254 | 0 | $data->{body} ||= []; | ||||
255 | 0 | $data->{footer} ||= ''; | ||||
256 | 0 | $self->{metadata} = Dump($data); | ||||
257 | 0 | $self->content($self->render_metadata); | ||||
258 | 0 | return $data; | ||||
259 | } else { | |||||
260 | 0 | return Load($self->{metadata}); | ||||
261 | } | |||||
262 | } | |||||
263 | ||||||
264 | # turn $object->metadata into a string suitable for $object->content | |||||
265 | sub render_metadata { | |||||
266 | 0 | my ($self, $format) = @_; | ||||
267 | 0 0 | $format ||= sub { $_[0] || "" }; | ||||
268 | 0 | my $metadata = $self->metadata; | ||||
269 | 0 | my $body = $metadata->{body}; | ||||
270 | 0 0 | my $text = join('', map { $format->($_) } @$body); | ||||
271 | 0 | return $metadata->{header} . $text . $metadata->{footer}; | ||||
272 | } | |||||
273 | ||||||
274 - 284 | =head3 $message->append(\%letter) If passed a hashref, this method will assume that the hashref is in the form that C<C4::Letters::getletter()> returns. It will append the body of the letter to the message. =head3 $message->append($string) If passed a string, it'll append the string to the message. =cut | |||||
285 | ||||||
286 | # $object->append($letter_or_item) -- add a new item to a message's content | |||||
287 | sub append { | |||||
288 | 0 | my ($self, $letter_or_item, $format) = @_; | ||||
289 | 0 | my $item; | ||||
290 | 0 | if (ref($letter_or_item)) { | ||||
291 | 0 | my $letter = $letter_or_item; | ||||
292 | 0 | my $metadata = _metadata($letter); | ||||
293 | 0 | $item = $metadata->{body}->[0]; | ||||
294 | } else { | |||||
295 | 0 | $item = $letter_or_item; | ||||
296 | } | |||||
297 | 0 | if (not $self->metadata) { | ||||
298 | 0 | carp "Can't append to messages that don't have metadata."; | ||||
299 | 0 | return undef; | ||||
300 | } | |||||
301 | 0 | my $metadata = $self->metadata; | ||||
302 | 0 0 | push @{$metadata->{body}}, $item; | ||||
303 | 0 | $self->metadata($metadata); | ||||
304 | 0 | my $new_content = $self->render_metadata($format); | ||||
305 | 0 | return $self->content($new_content); | ||||
306 | } | |||||
307 | ||||||
308 - 312 | =head2 Attributes Accessors =head3 $message->message_id =cut | |||||
313 | ||||||
314 - 316 | =head3 $message->borrowernumber =cut | |||||
317 | ||||||
318 - 320 | =head3 $message->subject =cut | |||||
321 | ||||||
322 - 324 | =head3 $message->content =cut | |||||
325 | ||||||
326 - 328 | =head3 $message->metadata =cut | |||||
329 | ||||||
330 - 332 | =head3 $message->letter_code =cut | |||||
333 | ||||||
334 - 336 | =head3 $message->message_transport_type =cut | |||||
337 | ||||||
338 - 340 | =head3 $message->status =cut | |||||
341 | ||||||
342 - 344 | =head3 $message->time_queued =cut | |||||
345 | ||||||
346 - 348 | =head3 $message->to_address =cut | |||||
349 | ||||||
350 - 352 | =head3 $message->from_address =cut | |||||
353 | ||||||
354 - 356 | =head3 $message->content_type =cut | |||||
357 | ||||||
358 | # $object->$method -- treat keys as methods | |||||
359 | sub AUTOLOAD { | |||||
360 | 0 | my ($self, @args) = @_; | ||||
361 | 0 | my $attr = $AUTOLOAD; | ||||
362 | 0 | $attr =~ s/.*://; | ||||
363 | 0 | if (ref($self->{$attr}) eq 'CODE') { | ||||
364 | 0 | $self->{$attr}->($self, @args); | ||||
365 | } else { | |||||
366 | 0 | if (@args) { | ||||
367 | 0 | $self->{$attr} = $args[0]; | ||||
368 | } else { | |||||
369 | 0 | $self->{$attr}; | ||||
370 | } | |||||
371 | } | |||||
372 | } | |||||
373 | ||||||
374 | 0 | sub DESTROY { } | ||||
375 | ||||||
376 | 1; | |||||
377 | ||||||
378 - 386 | =head1 SEE ALSO L<C4::Circulation>, L<C4::Letters>, L<C4::Members::Messaging> =head1 AUTHOR John Beppu <john.beppu@liblime.com> =cut |