moved qdb here because matt is lazy
[public/www-new.git] / pub / qdb / src / modules / Chirpy / DataManager.pm
1 ###############################################################################\r
2 # Chirpy! 0.3, a quote management system                                      #\r
3 # Copyright (C) 2005-2007 Tim De Pauw <ceetee@users.sourceforge.net>          #\r
4 ###############################################################################\r
5 # This program is free software; you can redistribute it and/or modify it     #\r
6 # under the terms of the GNU General Public License as published by the Free  #\r
7 # Software Foundation; either version 2 of the License, or (at your option)   #\r
8 # any later version.                                                          #\r
9 #                                                                             #\r
10 # This program is distributed in the hope that it will be useful, but WITHOUT #\r
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #\r
12 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #\r
13 # more details.                                                               #\r
14 #                                                                             #\r
15 # You should have received a copy of the GNU General Public License along     #\r
16 # with this program; if not, write to the Free Software Foundation, Inc., 51  #\r
17 # Franklin St, Fifth Floor, Boston, MA  02110-1301  USA                       #\r
18 ###############################################################################\r
19 \r
20 ###############################################################################\r
21 # $Id:: DataManager.pm 291 2007-02-05 21:24:46Z ceetee                      $ #\r
22 ###############################################################################\r
23 \r
24 =head1 NAME\r
25 \r
26 Chirpy::DataManager - Abstract data manager class\r
27 \r
28 =head1 IMPLEMENTATION\r
29 \r
30 This section should tell you just about everything you need to know if you want\r
31 to write your own Chirpy! data manager.\r
32 \r
33 First of all, it must be a class that extends this abstract class, and it must\r
34 have something along the lines of\r
35 \r
36   use vars qw($VERSION @ISA);\r
37   $VERSION = '0.3';\r
38   @ISA = qw(Chirpy::DataManager);\r
39 \r
40 All you need to do then, really, is implement this class's abstract methods.\r
41 Unfortunately, there are quite a few of them. However, a lot of them are fairly\r
42 trivial, as you will quickly learn. All of them are object methods.\r
43 \r
44 =head2 Compatibility\r
45 \r
46 =over 4\r
47 \r
48 =item get_target_version()\r
49 \r
50 The return value of this function is compared to Chirpy!'s version. If the\r
51 version numbers do not match, execution will be aborted. Hence, it needs to be\r
52 exactly the same as the version of Chirpy! the data manager was built for.\r
53 \r
54 =back\r
55 \r
56 =head2 Parameters\r
57 \r
58 =over 4\r
59 \r
60 =item get_parameter($name)\r
61 \r
62 Gets the value of a persistent parameter.\r
63 \r
64 =item set_parameter($name, $value)\r
65 \r
66 Sets the value of a persistent parameter.\r
67 \r
68 =back\r
69 \r
70 =head2 Installation & Removal\r
71 \r
72 =over 4\r
73 \r
74 =item set_up($accounts, $news, $quotes)\r
75 \r
76 Called at installation time, this method should create all necessary resources\r
77 to use the data manager. For instance, if the module uses a database, this\r
78 method should create the necessary tables in it.\r
79 \r
80 In addition, the method takes 3 arguments, each either an array reference or\r
81 C<undef>. They represent the initial data to be stored in the installation.\r
82 C<$accounts> holds instances of L<Chirpy::Account>, C<$news> instances of\r
83 L<Chirpy::NewsItem> and C<$quotes> instances of L<Chirpy::Quote>.\r
84 \r
85 =item remove()\r
86 \r
87 The exact opposite of the C<set_up()> method. Removes all applicable data.\r
88 \r
89 =back\r
90 \r
91 =head2 Quotes\r
92 \r
93 =over 4\r
94 \r
95 =item get_quotes($options)\r
96 \r
97 Accepts C<$options>, a reference to a hash containing parameters defining the\r
98 output, or C<undef>.\r
99 \r
100 In a scalar context, returns a reference to an array of matching quotes (as\r
101 instances of L<Chirpy::Quote>), or C<undef> if there are no matches. Otherwise,\r
102 returns that array, along with 2 boolean values. The first is true if there\r
103 are quotes I<before> the start of the results, the second is true if there are\r
104 quotes I<after> the end of the results.\r
105 \r
106 The option hash may contain any of the keys below. If multiple keys are\r
107 present, the properties they imply must I<all> apply to the resulting quotes.\r
108 \r
109 =over 8\r
110 \r
111 =item id\r
112 \r
113 ID of the quote to retrieve.\r
114 \r
115 =item contains\r
116 \r
117 Reference to an array of strings to find in either the quote body or notes. May\r
118 contain wildcard characters: an asterisk (C<*>) may represent any character\r
119 sequence, including an empty one; a question mark (C<?>) represents a single\r
120 character. To search for the wildcard characters themselves, they may be\r
121 prefixed with a backslash (C<\>). Consequently, backslashes themselves must\r
122 also be prefixed with a backslash.\r
123 \r
124 =item tags\r
125 \r
126 Reference to an array of tags, any of which must be a tag of the quote.\r
127 \r
128 =item approved\r
129 \r
130 Boolean value indicating the I<approved> status of the quote. Note that a false\r
131 value implies that the quotes must not be approved, while C<undef> cannot\r
132 affect the results.\r
133 \r
134 =item flagged\r
135 \r
136 Boolean value indicating the I<flagged> status of the quote. Note that a false\r
137 value implies that the quotes must not be flagged, while C<undef> cannot\r
138 affect the results.\r
139 \r
140 =item since\r
141 \r
142 UNIX timestamp representing the earliest date allowed for the date when quotes\r
143 were submitted.\r
144 \r
145 =item sort\r
146 \r
147 Properties of the quote to sort on, represented as a two-dimensional array\r
148 reference. Here is an example:\r
149 \r
150  [ [ 'score', 0 ], [ 'id', 1 ] ]\r
151 \r
152 The boolean value is true if the results should be in descending order. Hence,\r
153 the sorting instruction above means the data manager should sort by score\r
154 first, in ascending order. If the ratings are equal, then it should sort by ID,\r
155 in descending order.\r
156 \r
157 The possible properties to sort on are C<id>, C<rating>, C<approved>, C<score>,\r
158 and C<flagged>. It is assumed that sorting on the date when the quote was\r
159 submitted has the same effect as sorting on quote ID.\r
160 \r
161 Sorting on C<score> was introduced in Chirpy! 0.3 and is used to determine the\r
162 top and bottom quotes. Quotes' scores are calculated as follows:\r
163 \r
164                                    votes + rating\r
165                                   ---------------- + 1\r
166            positive votes + 1             2\r
167   score = -------------------- = ----------------------\r
168            negative votes + 1      votes - rating\r
169                                   ---------------- + 1\r
170                                           2\r
171 \r
172 Data managers may prefer to cache this value for performance purposes.\r
173 \r
174 =item random\r
175 \r
176 Boolean value indicating if results should be randomly selected. Overrides the\r
177 "sort" option.\r
178 \r
179 =item first\r
180 \r
181 The number of the first result to return, 0 being the first in the result list.\r
182 \r
183 =item count\r
184 \r
185 The number of quotes to maximally return.\r
186 \r
187 =back\r
188 \r
189 =item quote_count($options)\r
190 \r
191 Returns the number of quotes in the database, either approved, unapproved, or\r
192 both. Optionally accepts C<$options>, a reference to a hash of parameters\r
193 defining which quotes are to be counted. Currently, C<$options> may contain only\r
194 one parameter, namely C<approved>. If C<approved> is undefined, all quotes are\r
195 included in the count; if it is a true value, only approved quotes are included,\r
196 and vice versa.\r
197 \r
198 =item add_quote($quote)\r
199 \r
200 Adds the L<Chirpy::Quote|Chirpy::Quote> C<$quote> to the collection. Assigns an\r
201 ID to the quote and updates the object with it. Returns a true value upon\r
202 success.\r
203 \r
204 The properties to be saved by this method are I<body>, I<notes>, I<approved>\r
205 and I<tags>.\r
206 \r
207 =item modify_quote($quote)\r
208 \r
209 Updates the L<Chirpy::Quote|Chirpy::Quote> C<$quote> in the collection. Returns\r
210 a true value on success.\r
211 \r
212 The properties to be saved by this method are I<body> and I<notes>.\r
213 \r
214 =item remove_quote($quote)\r
215 \r
216 Removes the L<Chirpy::Quote|Chirpy::Quote> C<$quote> from the collection.\r
217 Returns a true value on success.\r
218 \r
219 =item remove_quotes(@ids)\r
220 \r
221 Removes all quotes whose ID is in C<@ids> from the collection. Returns the\r
222 number of removed quotes.\r
223 \r
224 =item increase_quote_rating($id, $revert)\r
225 \r
226 Increases the rating of quote number C<$id>. If C<$revert> is a true value,\r
227 increases the rating by 2, as the user is reverting his vote; otherwise,\r
228 increases it by 1. If the user is not reverting his vote, increases the number\r
229 of votes for the quote by 1 as well. Returns a list containing the updated\r
230 rating and vote count.\r
231 \r
232 =item decrease_quote_rating($id, $revert)\r
233 \r
234 Decreases the rating of quote number C<$id>. If C<$revert> is a true value,\r
235 decreases the rating by 2, as the user is reverting his vote; otherwise,\r
236 decreases it by 1. If the user is not reverting his vote, increases the number\r
237 of votes for the quote by 1 as well. Returns a list containing the updated\r
238 rating and vote count.\r
239 \r
240 =item get_tag_use_counts()\r
241 \r
242 Returns a reference to a hash, mapping tags to the number of times they were\r
243 used. Only tags for approved quotes should be counted.\r
244 \r
245 =item approve_quotes(@ids)\r
246 \r
247 Sets the quotes associated with an ID in C<@ids> to I<approved>. Returns the\r
248 number of affected quotes.\r
249 \r
250 =item unflag_quotes(@ids)\r
251 \r
252 Sets the quotes associated with an ID in C<@ids> to I<unflagged>. Returns the\r
253 number of affected quotes.\r
254 \r
255 =back\r
256 \r
257 =head2 News Items\r
258 \r
259 =over 4\r
260 \r
261 =item get_news_items($options)\r
262 \r
263 Retrieves news items, a lot like L<get_quotes()|/get_quotes($options)>\r
264 retrieves quotes. The possible options are now:\r
265 \r
266 =over 8\r
267 \r
268 =item id\r
269 \r
270 ID of the news item to retrieve.\r
271 \r
272 =item count\r
273 \r
274 Maximum number of news items returned.\r
275 \r
276 =back\r
277 \r
278 Resulting news items are always sorted by date, newest first.\r
279 \r
280 The function returns a reference to an array of instances of\r
281 L<Chirpy::NewsItem>, or C<undef> if no matching news items were found.\r
282 \r
283 =item add_news_item($news_item)\r
284 \r
285 Adds the L<Chirpy::NewsItem|Chirpy::NewsItem> C<$news_item> to the collection.\r
286 Assigns an ID to the news item and updates the object with it. Returns a true\r
287 value upon success.\r
288 \r
289 The properties to be saved by this method are I<body> and I<poster>. I<poster>\r
290 may be C<undef> if the poster is unknown.\r
291 \r
292 =item modify_news_item($news_item)\r
293 \r
294 Updates the L<Chirpy::NewsItem|Chirpy::NewsItem> C<$news_item> in the\r
295 collection. Returns a true value on success.\r
296 \r
297 The properties to be saved by this method are I<body> and I<poster>. I<poster>\r
298 may be C<undef> if the poster is unknown.\r
299 \r
300 =item remove_news_item($news_item)\r
301 \r
302 Removes the L<Chirpy::NewsItem|Chirpy::NewsItem> C<$news_item> from the\r
303 collection. Returns a true value on success.\r
304 \r
305 =item remove_news_items(@ids)\r
306 \r
307 Removes all news items whose ID is in C<@ids> from the collection. Returns the\r
308 number of removed news items.\r
309 \r
310 =back\r
311 \r
312 =head2 User Accounts\r
313 \r
314 =over 4\r
315 \r
316 =item get_accounts($options)\r
317 \r
318 Retrieves accounts, a lot like L<get_quotes()|/get_quotes($options)> retrieves\r
319 quotes and L<get_news_items()|/get_news_items($options)> retrieves news items.\r
320 The possible options are now:\r
321 \r
322 =over 8\r
323 \r
324 =item id\r
325 \r
326 ID of the account to retrieve.\r
327 \r
328 =item username\r
329 \r
330 User name of the account to retrieve.\r
331 \r
332 =item levels\r
333 \r
334 Reference to an array containing allowed user levels.\r
335 \r
336 =back\r
337 \r
338 Resulting accounts are always sorted by user level, highest first, then by user\r
339 name.\r
340 \r
341 The function returns a reference to an array of instances of\r
342 L<Chirpy::Account>, or C<undef> if no matching accounts were found.\r
343 \r
344 =item add_account($account)\r
345 \r
346 Adds the L<Chirpy::Account|Chirpy::Account> C<$account> to the collection.\r
347 Assigns an ID to the account and updates the object with it. Returns a true\r
348 value upon success.\r
349 \r
350 The properties to be saved by this method are I<username>, I<password> and\r
351 I<level>.\r
352 \r
353 =item modify_account($account)\r
354 \r
355 Updates the L<Chirpy::Account|Chirpy::Account> C<$account> in the collection.\r
356 Returns a true value on success.\r
357 \r
358 The properties to be saved by this method are I<username>, I<password> and\r
359 I<level>.\r
360 \r
361 =item remove_account($account)\r
362 \r
363 Removes the L<Chirpy::Account|Chirpy::Account> C<$account> from the collection.\r
364 Returns a true value on success.\r
365 \r
366 Note that upon removal of an account, news items associated with it must be\r
367 kept, but their author becomes unknown.\r
368 \r
369 =item remove_accounts(@ids)\r
370 \r
371 Removes all accounts whose ID is in C<@ids> from the collection. Returns the\r
372 number of removed accounts.\r
373 \r
374 Note that upon removal of an account, news items associated with it must be\r
375 kept, but their author becomes unknown.\r
376 \r
377 =item username_exists($username)\r
378 \r
379 Returns a true value if the given username exists in the collection.\r
380 \r
381 =item account_count($params)\r
382 \r
383 Returns the current number of accounts. Takes an optional hash reference to\r
384 retrieval options. For now, it can only contain the key C<levels>, whose value\r
385 is a reference to an array of user levels. If this key is set, the function\r
386 returns the number of accounts with any of those levels.\r
387 \r
388 =back\r
389 \r
390 =head2 Logging\r
391 \r
392 =over 4\r
393 \r
394 =item get_events($options)\r
395 \r
396 Retrieves log events, taking a hash reference like the other C<get_> functions.\r
397 Returns results in the same fashion as L<get_quotes()|/get_quotes($options)>,\r
398 but always sorted chronologically. This time, the available options are:\r
399 \r
400 =over 8\r
401 \r
402 =item code\r
403 \r
404 Either a single event code or a reference to an array of codes to match. This\r
405 option may be omitted.\r
406 \r
407 =item user\r
408 \r
409 Either a single user ID or a reference to an array of IDs to match. This option\r
410 may be omitted. A user ID of 0 represents users who are not logged in.\r
411 \r
412 =item first\r
413 \r
414 The number of the first result to return, 0 being the first in the result list.\r
415 If this option is omitted, the default value of 0 is assumed.\r
416 \r
417 =item count\r
418 \r
419 The number of events to maximally return. If this option is omitted, there is\r
420 no limit on the number of results.\r
421 \r
422 =item reverse\r
423 \r
424 If this option has a true value, the order is reversed, so the events are in\r
425 reverse chronological order.\r
426 \r
427 =item data\r
428 \r
429 May be set to a hash reference to filter the events on metadata. If any of the\r
430 key-value pairs in the hash are equal to a metadata property of the event, it\r
431 is considered a match. This option may be omitted.\r
432 \r
433 =back\r
434 \r
435 =item log_event($event)\r
436 \r
437 Logs the L<Chirpy::Event|Chirpy::Event> C<$event>. Returns a true value on\r
438 success.\r
439 \r
440 The properties to be saved by this method are I<code>, I<user> and I<data>.\r
441 \r
442 =back\r
443 \r
444 =head2 Sessions\r
445 \r
446 I<This step is optional.>\r
447 \r
448 In addition, you may want to provide compatibility with\r
449 L<Chirpy::UI::WebApp|Chirpy::UI::WebApp>'s session manager by making your data\r
450 manager class extend L<Chirpy::UI::WebApp::Session::DataManager> as well.\r
451 Please check L<its documentation|Chirpy::UI::WebApp::Session::DataManager> for\r
452 instructions.\r
453 \r
454 =head1 AUTHOR\r
455 \r
456 Tim De Pauw E<lt>ceetee@users.sourceforge.netE<gt>\r
457 \r
458 =head1 SEE ALSO\r
459 \r
460 L<Chirpy::Quote>, L<Chirpy::NewsItem>, L<Chirpy::Account>, L<Chirpy::Event>,\r
461 L<Chirpy::DataManager::MySQL>, L<Chirpy::UI::WebApp::Session::DataManager>,\r
462 L<Chirpy>, L<http://chirpy.sourceforge.net/>\r
463 \r
464 =head1 COPYRIGHT\r
465 \r
466 Copyright 2005-2007 Tim De Pauw. All rights reserved.\r
467 \r
468 This program is free software; you can redistribute it and/or modify it under\r
469 the terms of the GNU General Public License as published by the Free Software\r
470 Foundation; either version 2 of the License, or (at your option) any later\r
471 version.\r
472 \r
473 This program is distributed in the hope that it will be useful, but WITHOUT ANY\r
474 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\r
475 PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
476 \r
477 =cut\r
478 \r
479 package Chirpy::DataManager;\r
480 \r
481 use strict;\r
482 use warnings;\r
483 \r
484 use vars qw($VERSION);\r
485 \r
486 $VERSION = '0.3';\r
487 \r
488 use Chirpy 0.3;\r
489 use Chirpy::Util 0.3;\r
490 \r
491 sub new {\r
492         my ($class, $params) = @_;\r
493         return bless {\r
494                 'params' => $params\r
495         }, $class;\r
496 }\r
497 \r
498 sub param {\r
499         my ($self, $name) = @_;\r
500         return defined $self->{'params'} ? $self->{'params'}{$name} : undef;\r
501 }\r
502 \r
503 *get_target_version = \&Chirpy::Util::abstract_method;\r
504 \r
505 *set_up = \&Chirpy::Util::abstract_method;\r
506 \r
507 *remove = \&Chirpy::Util::abstract_method;\r
508 \r
509 *get_quote = \&Chirpy::Util::abstract_method;\r
510 \r
511 *quote_count = \&Chirpy::Util::abstract_method;\r
512 \r
513 *get_quotes = \&Chirpy::Util::abstract_method;\r
514 \r
515 *add_quote = \&Chirpy::Util::abstract_method;\r
516 \r
517 *modify_quote = \&Chirpy::Util::abstract_method;\r
518 \r
519 *increase_quote_rating = \&Chirpy::Util::abstract_method;\r
520 \r
521 *decrease_quote_rating = \&Chirpy::Util::abstract_method;\r
522 \r
523 *get_tag_use_counts = \&Chirpy::Util::abstract_method;\r
524 \r
525 *approve_quotes = \&Chirpy::Util::abstract_method;\r
526 \r
527 *flag_quotes = \&Chirpy::Util::abstract_method;\r
528 \r
529 *unflag_quotes = \&Chirpy::Util::abstract_method;\r
530 \r
531 *remove_quote = \&Chirpy::Util::abstract_method;\r
532 \r
533 *remove_quotes = \&Chirpy::Util::abstract_method;\r
534 \r
535 *get_news_items = \&Chirpy::Util::abstract_method;\r
536 \r
537 *add_news_item = \&Chirpy::Util::abstract_method;\r
538 \r
539 *modify_news_item = \&Chirpy::Util::abstract_method;\r
540 \r
541 *remove_news_item = \&Chirpy::Util::abstract_method;\r
542 \r
543 *remove_news_items = \&Chirpy::Util::abstract_method;\r
544 \r
545 *get_accounts = \&Chirpy::Util::abstract_method;\r
546 \r
547 *add_account = \&Chirpy::Util::abstract_method;\r
548 \r
549 *modify_account = \&Chirpy::Util::abstract_method;\r
550 \r
551 *remove_account = \&Chirpy::Util::abstract_method;\r
552 \r
553 *remove_accounts = \&Chirpy::Util::abstract_method;\r
554 \r
555 *username_exists = \&Chirpy::Util::abstract_method;\r
556 \r
557 *account_count = \&Chirpy::Util::abstract_method;\r
558 \r
559 *get_events = \&Chirpy::Util::abstract_method;\r
560 \r
561 *log_event = \&Chirpy::Util::abstract_method;\r
562 \r
563 *get_parameter = \&Chirpy::Util::abstract_method;\r
564 \r
565 *set_parameter = \&Chirpy::Util::abstract_method;\r
566 \r
567 1;\r
568 \r
569 ###############################################################################