File: | C4/Message.pm |
Coverage: | 14.3% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package C4::Message; | |||||
2 | 24 24 24 | 41768 156 824 | use strict; | |||
3 | 24 24 24 | 221 177 969 | use warnings; | |||
4 | 24 24 24 | 587 164 335 | use C4::Context; | |||
5 | 24 24 24 | 579 145 4022 | use C4::Letters; | |||
6 | 24 24 24 | 246 112 2049 | use YAML::Syck; | |||
7 | 24 24 24 | 182 146 36155 | use Carp; | |||
8 | ||||||
9 - 42 | =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::getletter('circulation', 'CHECKOUT'); C4::Letters::parseletter($letter, 'biblio', $item->{biblionumber}); C4::Letters::parseletter($letter, '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 | |||||
43 | ||||||
44 | ||||||
45 | our $AUTOLOAD; | |||||
46 | ||||||
47 | ||||||
48 - 54 | =head2 Class Methods =head3 C4::Message->new(\%attributes) This method creates an in-memory version of a message object. =cut | |||||
55 | ||||||
56 | # C4::Message->new(\%attributes) -- constructor | |||||
57 | sub new { | |||||
58 | 0 | my ($class, $opts) = @_; | ||||
59 | 0 | $opts ||= {}; | ||||
60 | 0 | bless {%$opts} => $class; | ||||
61 | } | |||||
62 | ||||||
63 | ||||||
64 - 69 | =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 | |||||
70 | ||||||
71 | # C4::Message->find($id) -- find a message by its message_id | |||||
72 | sub find { | |||||
73 | 0 | my ($class, $id) = @_; | ||||
74 | 0 | my $dbh = C4::Context->dbh; | ||||
75 | 0 | my $msgs = $dbh->selectall_arrayref( | ||||
76 | qq{SELECT * FROM message_queue WHERE message_id = ?}, | |||||
77 | { Slice => {} }, | |||||
78 | $id, | |||||
79 | ); | |||||
80 | 0 | if (@$msgs) { | ||||
81 | 0 | return $class->new($msgs->[0]); | ||||
82 | } else { | |||||
83 | 0 | return undef; | ||||
84 | } | |||||
85 | } | |||||
86 | ||||||
87 - 93 | =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 | |||||
94 | ||||||
95 | # C4::Message->find_last_message($borrower, $letter_code, $transport) | |||||
96 | # -- get the borrower's most recent pending checkin or checkout notification | |||||
97 | sub find_last_message { | |||||
98 | 0 | my ($class, $borrower, $letter_code, $transport) = @_; | ||||
99 | # $type is the message_transport_type | |||||
100 | 0 | $transport ||= 'email'; | ||||
101 | 0 | my $dbh = C4::Context->dbh; | ||||
102 | 0 | my $msgs = $dbh->selectall_arrayref( | ||||
103 | qq{ | |||||
104 | SELECT * | |||||
105 | FROM message_queue | |||||
106 | WHERE status = 'pending' | |||||
107 | AND borrowernumber = ? | |||||
108 | AND letter_code = ? | |||||
109 | AND message_transport_type = ? | |||||
110 | }, | |||||
111 | { Slice => {} }, | |||||
112 | $borrower->{borrowernumber}, | |||||
113 | $letter_code, | |||||
114 | $transport, | |||||
115 | ); | |||||
116 | 0 | if (@$msgs) { | ||||
117 | 0 | return $class->new($msgs->[0]); | ||||
118 | } else { | |||||
119 | 0 | return undef; | ||||
120 | } | |||||
121 | } | |||||
122 | ||||||
123 | ||||||
124 - 129 | =head3 C4::Message->enqueue($letter, $borrower, $transport) This is a front-end for C<C4::Letters::EnqueueLetter()> that adds metadata to the message. =cut | |||||
130 | ||||||
131 | # C4::Message->enqueue($letter, $borrower, $transport) | |||||
132 | sub enqueue { | |||||
133 | 0 | my ($class, $letter, $borrower, $transport) = @_; | ||||
134 | 0 | my $metadata = _metadata($letter); | ||||
135 | 0 | my $to_address = _to_address($borrower, $transport); | ||||
136 | 0 | $letter->{metadata} = Dump($metadata); | ||||
137 | #carp "enqueuing... to $to_address"; | |||||
138 | 0 | C4::Letters::EnqueueLetter({ | ||||
139 | letter => $letter, | |||||
140 | borrowernumber => $borrower->{borrowernumber}, | |||||
141 | message_transport_type => $transport, | |||||
142 | to_address => $to_address, | |||||
143 | }); | |||||
144 | } | |||||
145 | ||||||
146 | # based on message $transport, pick an appropriate address to send to | |||||
147 | sub _to_address { | |||||
148 | 0 | my ($borrower, $transport) = @_; | ||||
149 | 0 | my $address; | ||||
150 | 0 | if ($transport eq 'email') { | ||||
151 | 0 | $address = $borrower->{email} | ||||
152 | || $borrower->{emailpro} | |||||
153 | || $borrower->{B_email}; | |||||
154 | } elsif ($transport eq 'sms') { | |||||
155 | 0 | $address = $borrower->{smsalertnumber} | ||||
156 | || $borrower->{phone} | |||||
157 | || $borrower->{phonepro} | |||||
158 | || $borrower->{B_phone}; | |||||
159 | } else { | |||||
160 | 0 | warn "'$transport' is an unknown message transport."; | ||||
161 | } | |||||
162 | 0 | if (not defined $address) { | ||||
163 | 0 | warn "An appropriate $transport address " | ||||
164 | . "for borrower $borrower->{userid} " | |||||
165 | . "could not be found."; | |||||
166 | } | |||||
167 | 0 | return $address; | ||||
168 | } | |||||
169 | ||||||
170 | # _metadata($letter) -- return the letter split into head/body/footer | |||||
171 | sub _metadata { | |||||
172 | 0 | my ($letter) = @_; | ||||
173 | 0 | if ($letter->{content} =~ /----/) { | ||||
174 | 0 | my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content}); | ||||
175 | return { | |||||
176 | 0 | header => $header, | ||||
177 | body => [$body], | |||||
178 | footer => $footer, | |||||
179 | }; | |||||
180 | } else { | |||||
181 | return { | |||||
182 | 0 | header => '', | ||||
183 | body => [$letter->{content}], | |||||
184 | footer => '', | |||||
185 | }; | |||||
186 | } | |||||
187 | } | |||||
188 | ||||||
189 - 196 | =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 | |||||
197 | ||||||
198 | # $object->update -- save object to database | |||||
199 | sub update { | |||||
200 | 0 | my ($self) = @_; | ||||
201 | 0 | my $dbh = C4::Context->dbh; | ||||
202 | 0 | $dbh->do( | ||||
203 | qq{ | |||||
204 | UPDATE message_queue | |||||
205 | SET | |||||
206 | borrowernumber = ?, | |||||
207 | subject = ?, | |||||
208 | content = ?, | |||||
209 | metadata = ?, | |||||
210 | letter_code = ?, | |||||
211 | message_transport_type = ?, | |||||
212 | status = ?, | |||||
213 | time_queued = ?, | |||||
214 | to_address = ?, | |||||
215 | from_address = ?, | |||||
216 | content_type = ? | |||||
217 | WHERE message_id = ? | |||||
218 | }, | |||||
219 | {}, | |||||
220 | $self->borrowernumber, | |||||
221 | $self->subject, | |||||
222 | $self->content, | |||||
223 | $self->{metadata}, # we want the raw YAML here | |||||
224 | $self->letter_code, | |||||
225 | $self->message_transport_type, | |||||
226 | $self->status, | |||||
227 | $self->time_queued, | |||||
228 | $self->to_address, | |||||
229 | $self->from_address, | |||||
230 | $self->content_type, | |||||
231 | $self->message_id | |||||
232 | ); | |||||
233 | } | |||||
234 | ||||||
235 - 240 | =head3 $message->metadata(\%new_metadata) This method automatically serializes and deserializes the metadata attribute. (It is stored in YAML format.) =cut | |||||
241 | ||||||
242 | # $object->metadata -- this is a YAML serialized column that contains a | |||||
243 | # structured representation of $object->content | |||||
244 | sub metadata { | |||||
245 | 0 | my ($self, $data) = @_; | ||||
246 | 0 | if ($data) { | ||||
247 | 0 | $data->{header} ||= ''; | ||||
248 | 0 | $data->{body} ||= []; | ||||
249 | 0 | $data->{footer} ||= ''; | ||||
250 | 0 | $self->{metadata} = Dump($data); | ||||
251 | 0 | $self->content($self->render_metadata); | ||||
252 | 0 | return $data; | ||||
253 | } else { | |||||
254 | 0 | return Load($self->{metadata}); | ||||
255 | } | |||||
256 | } | |||||
257 | ||||||
258 | # turn $object->metadata into a string suitable for $object->content | |||||
259 | sub render_metadata { | |||||
260 | 0 | my ($self, $format) = @_; | ||||
261 | 0 0 | $format ||= sub { $_[0] || "" }; | ||||
262 | 0 | my $metadata = $self->metadata; | ||||
263 | 0 | my $body = $metadata->{body}; | ||||
264 | 0 0 | my $text = join('', map { $format->($_) } @$body); | ||||
265 | 0 | return $metadata->{header} . $text . $metadata->{footer}; | ||||
266 | } | |||||
267 | ||||||
268 - 278 | =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 | |||||
279 | ||||||
280 | # $object->append($letter_or_item) -- add a new item to a message's content | |||||
281 | sub append { | |||||
282 | 0 | my ($self, $letter_or_item, $format) = @_; | ||||
283 | 0 | my $item; | ||||
284 | 0 | if (ref($letter_or_item)) { | ||||
285 | 0 | my $letter = $letter_or_item; | ||||
286 | 0 | my $metadata = _metadata($letter); | ||||
287 | 0 | $item = $metadata->{body}->[0]; | ||||
288 | } else { | |||||
289 | 0 | $item = $letter_or_item; | ||||
290 | } | |||||
291 | 0 | if (not $self->metadata) { | ||||
292 | 0 | carp "Can't append to messages that don't have metadata."; | ||||
293 | 0 | return undef; | ||||
294 | } | |||||
295 | 0 | my $metadata = $self->metadata; | ||||
296 | 0 0 | push @{$metadata->{body}}, $item; | ||||
297 | 0 | $self->metadata($metadata); | ||||
298 | 0 | my $new_content = $self->render_metadata($format); | ||||
299 | 0 | return $self->content($new_content); | ||||
300 | } | |||||
301 | ||||||
302 - 306 | =head2 Attributes Accessors =head3 $message->message_id =cut | |||||
307 | ||||||
308 - 310 | =head3 $message->borrowernumber =cut | |||||
311 | ||||||
312 - 314 | =head3 $message->subject =cut | |||||
315 | ||||||
316 - 318 | =head3 $message->content =cut | |||||
319 | ||||||
320 - 322 | =head3 $message->metadata =cut | |||||
323 | ||||||
324 - 326 | =head3 $message->letter_code =cut | |||||
327 | ||||||
328 - 330 | =head3 $message->message_transport_type =cut | |||||
331 | ||||||
332 - 334 | =head3 $message->status =cut | |||||
335 | ||||||
336 - 338 | =head3 $message->time_queued =cut | |||||
339 | ||||||
340 - 342 | =head3 $message->to_address =cut | |||||
343 | ||||||
344 - 346 | =head3 $message->from_address =cut | |||||
347 | ||||||
348 - 350 | =head3 $message->content_type =cut | |||||
351 | ||||||
352 | # $object->$method -- treat keys as methods | |||||
353 | sub AUTOLOAD { | |||||
354 | 0 | my ($self, @args) = @_; | ||||
355 | 0 | my $attr = $AUTOLOAD; | ||||
356 | 0 | $attr =~ s/.*://; | ||||
357 | 0 | if (ref($self->{$attr}) eq 'CODE') { | ||||
358 | 0 | $self->{$attr}->($self, @args); | ||||
359 | } else { | |||||
360 | 0 | if (@args) { | ||||
361 | 0 | $self->{$attr} = $args[0]; | ||||
362 | } else { | |||||
363 | 0 | $self->{$attr}; | ||||
364 | } | |||||
365 | } | |||||
366 | } | |||||
367 | ||||||
368 | 0 | sub DESTROY { } | ||||
369 | ||||||
370 | 1; | |||||
371 | ||||||
372 - 380 | =head1 SEE ALSO L<C4::Circulation>, L<C4::Letters>, L<C4::Members::Messaging> =head1 AUTHOR John Beppu <john.beppu@liblime.com> =cut |