/[drupal]/contributions/modules/birthdays/birthdays.module
ViewVC logotype

Contents of /contributions/modules/birthdays/birthdays.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.33 - (show annotations) (download) (as text)
Tue Oct 14 07:16:03 2008 UTC (13 months, 2 weeks ago) by maartenvg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.32: +2 -2 lines
File MIME type: text/x-php
#320218 by BENNYSOFT: Drupal-conform more-link or Birthdays block.
1 <?php
2 // $Id: birthdays.module,v 1.32 2008/10/10 07:53:34 maartenvg Exp $
3 /**
4 * @file
5 * The Birthdays module allows users to add their birthday to their
6 * profile. It lists birthdays on a seperate page and in different
7 * blocks. Users can receive an e-mail on their birthday automatically,
8 * and the administrator can receive daily reminders of who are having
9 * their birthday. Requires Profile Module.
10 */
11
12 /**
13 * Global variable which contains the field that was selected as Birthdays
14 * field.
15 */
16 global $_birthdays_field;
17
18 /**
19 * Admin e-mails disabled. Default.
20 */
21 define('BIRTHDAYS_ADMIN_MAIL_DISABLED', '0');
22
23 /**
24 * Admin e-mails should be sent dayly.
25 */
26 define('BIRTHDAYS_ADMIN_MAIL_DAILY', '1');
27
28 /**
29 * Admin e-mails should be sent weekly, on the first day of the week defined
30 * by 'admin/settings/date-time'.
31 */
32 define('BIRTHDAYS_ADMIN_MAIL_WEEKLY', '2');
33
34 /**
35 * Admin e-mails should be sent monthly, on the first day of the month.
36 */
37 define('BIRTHDAYS_ADMIN_MAIL_MONTHLY', '3');
38
39
40 /**
41 * Do not show starsigns. Default.
42 */
43 define('BIRTHDAYS_STARSIGN_OFF', '0');
44
45 /**
46 * Show starsigns, with link to Yahoo.
47 */
48 define('BIRTHDAYS_STARSIGN_LINK', '1');
49
50 /**
51 * Show starsigns, image only.
52 */
53 define('BIRTHDAYS_STARSIGN_NOLINK', '2');
54
55 /**
56 * Do not hide the year of birth and age of users. This goes for all pages
57 * generated by the Birthdays module. Default.
58 */
59 define('BIRTHDAYS_HIDE_YEAR_NO', '0');
60
61 /**
62 * Hide the year of birth and age of users. This goes for all pages
63 * generated by the Birthdays module.
64 */
65 define('BIRTHDAYS_HIDE_YEAR_YES', '1');
66
67 /**
68 * Hiding or showing the year of birth and age is up to the user. This goes
69 * for all pages generated by the Birthdays module.
70 */
71 define('BIRTHDAYS_HIDE_YEAR_USER', '2');
72
73 /**
74 * User does not want the birth year and age to be hidden. Used when
75 * hiding the year is an user option.
76 */
77 define('BIRTHDAYS_HIDE_YEAR_USER_NO', '0');
78
79 /**
80 * User wants birth year and age to be hidden. Used when
81 * hiding the year is an user option.
82 */
83 define('BIRTHDAYS_HIDE_YEAR_USER_YES', '1');
84 /**
85 * Do not show users without a birthday on the Birthdays listing
86 * and sort by birthday. Default.
87 */
88 define('BIRTHDAYS_PAGE_FILTER_SORT_DATE', '0');
89
90 /**
91 * Do not show users without a birthday on the Birthdays listing
92 * and sort by username.
93 */
94 define('BIRTHDAYS_PAGE_FILTER_SORT_USER', '1');
95
96 /**
97 * Show all users on the Birthdays listing and sort by username.
98 */
99 define('BIRTHDAYS_PAGE_NOFILTER_SORT_USER', '2');
100
101 /**
102 * Do not send an e-mail to the user on their birthday. Default.
103 */
104 define('BIRTHDAYS_USER_MAIL_NO', '0');
105
106 /**
107 * Send an e-mail to the user on their birthday.
108 */
109 define('BIRTHDAYS_USER_MAIL_YES', '1');
110
111 /**
112 * Sending an e-mail to the user depends on that user's preference.
113 */
114 define('BIRTHDAYS_USER_MAIL_USER', '2');
115
116 /**
117 * User doesn't want to be e-mailed on their birthday.
118 */
119 define('BIRTHDAYS_USER_MAIL_USER_NO', '1');
120
121 /**
122 * User wants to be e-mailed on their birthday.
123 */
124 define('BIRTHDAYS_USER_MAIL_USER_YES', '0');
125
126 /**
127 * Implementation of hook_init().
128 */
129 function birthdays_init() {
130 global $_birthdays_field;
131 $_birthdays_field = _birthdays_get_field(variable_get('birthdays_field_id', NULL));
132 }
133
134 /**
135 * Implementation of hook_help().
136 */
137 function birthdays_help($path, $arg) {
138 global $_birthdays_field;
139 switch ($path) {
140 case 'admin/help#birthdays':
141 $output = '<p>' . t("The Birthdays module allows a user to put in their birthday and display it in their profile, on a separate Birthdays page and in a block. It also has the option to send out e-mails on users's birthdays, and to notify the administrator periodically about upcoming birthdays via e-mail.") . '</p>';
142 $output .= '<p>' . t('Some basic information about this module can be found below. For more information, support questions, feature requests and bug reports please visit the <a href="@project_url">Birthdays project page</a> and the <a href="@documentation_url">online documentation</a>.', array('@project_url' => 'http://drupal.org/project/birthdays', '@documentation_url' => 'http://drupal.org/node/315658')) . '</p>';
143 $output .= '<h2>' . t('Configuring the module') . '</h2>';
144 $output .= '<p>' . t('Configuring the module is done on a number of pages.') . '</p>';
145 $output .= '<h3>' . t('Birthdays administration pages') . '</h3>';
146 $output .= '<p>' . t('The <a href="@birthdays_admin">Birthdays administration pages</a> are where the actual features of the birthdays module are set. Some of the options are described below.', array('@birthdays_admin' => url('admin/settings/birthdays'))) . '</p>';
147 $output .= '<ul><li><strong>' . t('Profile field') . '</strong>: ' . t('here you set which "date" field of the Profile module you want the Birthdays module to use.') . '</li>';
148 $output .= '<li><strong>' . t('Show star signs') . '</strong>: ' . t('select whether you want to display the star sign icons on the profile and on the Birthdays page, and, if so, whether it should link to Yahoo Horoscopes.') . '</li>';
149 $output .= '<li><strong>' . t('Hide year and age') . '</strong>: ' . t("some sites might want to protect the user's privacy by hiding their age and year of birth. The options are 'No', 'Yes' and 'User optional, defaults to No', where the latter gives the user the option to select whether he or she wants this information to be hidden. If enabled it still requires them to put the full date of birth in, but only the day and month will be displayed.") . '</li>';
150 $output .= '<li><strong>' . t('Set Birthdays page settings') . '</strong>: ' . t('this influences how the listing of the Birthdays page is shown. Sorted by user name of date of birth (year not included) and users without a birthday shown or not.') . '</li>';
151 $output .= '<li><strong>' . t('Show filter options') . '</strong>: ' . t("determine whether the buttons to filter by specific month and/or year should be displayed. When 'Hide year and age' is set to 'Yes', filtering by year is not possible.") . '</li>';
152 $output .= '<li><strong>' . t('Send upcoming birthdays to admin') . '</strong>: ' . t("this one has 4 values 'Disabled', 'Dayly', 'Weekly, on the first day of the week' and 'Monthly'. This will send an e-mail to your site e-mail address at the given intervals, listing users that will have their birthday in that period. The first day of the week is controlled by the <a href=\"@date_settings\">date and time settings</a>.", array('@date_settings' => url('admin/settings/date-time'))) . '</li>';
153 $output .= '<li><strong>' . t('Send user e-mail on day of birth') . '</strong>: ' . t("set whether users should receive an e-mail when they are having the birthday. Either 'No', 'Yes' or 'User optional, 'Yes' by default', where the latter leaves the decision up to the user.") . '</li></ul>';
154
155 $output .= '<h3>' . t('Permissions') . '</h3>';
156 $output .= '<p>' . t('To allow users to view birthdays of other people, the "access birthdays" <a href="@permissions_page">permissions</a> needs to be set for the appropriate role. This allows them to access the <a href="@birthdays_page">Birthdays page</a>, see activated blocks with birthdays and view the birthdays of users in the profiles.', array('@birthdays_page' => url('birthdays'), '@permissions_page' => url('admin/user/permissions', array('fragment' => 'module-birthdays')))) . '</p>';
157
158 $output .= '<h3>' . t('Profile field settings') . '</h3>';
159
160 $output .= '<p>' . t("Several things can be adjusted to the assigned profile field. To do so please visit the !profile_admin, and edit the field in question or add one if you haven't done so already. The following settings require extra attention.", array('!profile_admin' => l('Profile settings', 'admin/user/profile'))) . '</p>';
161
162 $output .= '<ul><li><strong>' . t('The user must enter a value') . '</strong>: ' . t('force the user to fill in their date of birth. A once set birthday can not be deleted.') . '</li>';
163 $output .= '<li><strong>' . t('Visible in user registration form') . '</strong>: ' . t('give new users the option to add their date of birth when registering to your website. If combined with the option above, they can not register without putting their date of birth.') . '</li>';
164 $output .= '<li><strong>' . t('Visibility') . '</strong>: ' . t("this will influence the visibility of the field as described there, but the behavior might become erratic if not set to 'Public field, content shown on profile page but not used on member list pages'. So it is recommended to leave this as is.") . '</li></ul>';
165 $output .= '<p>' . t('The other options on this page behave as described on the settings page.') . '</p>';
166
167 $output .= '<h3>' . t('Date format') . '</h3>';
168 $output .= '<p>' . t('The way the birthdays are formatted (e.g. <em>11 may 1934</em> or <em>5/11/1934</em>) is controlled by the <a href="@date_settings_page">date and time settings</a>. The Birthdays module uses the short date format as basis for displaying days and months in the blocks and the medium date format is used in the profile and on the Birthdays page.', array('!date_settings_page' => url('admin/settings/date-time'))) . '</p>';
169
170 $output .= '<h2>' . t('Synchronizing') . '</h2>';
171
172 $output .= '<p>' . t('The birthdays are saved to two different database tables. This is because the profile module saves the dates in a format which limits the ability to perform calculations on the dates. These two tables need to be in sync with each other.') . '</p>';
173 $output .= '<p>' . t('Normally this is the case, but sometimes not. For example when you already collected birthdays with the Profile module, but later decided to switch to the birthdays module. Or when you accidentally (on intentionally) completely uninstalled the profile module, but left birthdays module merely disabled. To perform the synchronization you can use the <a href="@sync_pages">synchronization form</a>.', array('@sync_page' => url('admin/settings/birthdays/sync'))) . '</p>';
174 $output .= '<p>' . t('In the first case you need to copy the Profile data to the (most likely empty) Birthdays table, which is done with the top button. In the latter you need the copy the birthdays in the Birthdays table back to the Profile module with the bottom button.') . '</p>';
175 $output .= '<p>' . t('Please note that with a large amount of users this might take some time.') . '</p>';
176
177 return $output;
178 case 'admin/settings/birthdays':
179 return t('Use this page to alter the settings of the Birthdays module.');
180 }
181 }
182
183
184 /**
185 * Implementation of hook_menu().
186 */
187 function birthdays_menu() {
188 $items['admin/settings/birthdays'] = array(
189 'title' => 'Birthdays',
190 'description' => 'Set user birthday mail and toggle user mail, upcoming birthdays mail and more.',
191 'page callback' => 'drupal_get_form',
192 'page arguments' => array('birthdays_admin_settings'),
193 'access arguments' => array('administer site configuration'),
194 'file' => 'birthdays.admin.inc',
195 );
196
197 $items['admin/settings/birthdays/settings'] = array(
198 'title' => 'Settings',
199 'type' => MENU_DEFAULT_LOCAL_TASK,
200 );
201
202 $items['admin/settings/birthdays/sync'] = array(
203 'title' => 'Synchronize',
204 'description' => 'Synchronize birthdays information of Profile module and Birthdays module. Used either when updating to a newer version of Birthdays or when integrating with an existing Profile Field.',
205 'page callback' => 'drupal_get_form',
206 'page arguments' => array('birthdays_sync_form'),
207 'access arguments' => array('administer site configuration'),
208 'type' => MENU_LOCAL_TASK,
209 'file' => 'birthdays.sync.inc',
210 );
211
212 $items['birthdays'] = array(
213 'title' => 'Birthdays',
214 'description' => 'List the birthdays of all users.',
215 'page callback' => 'birthdays_view_page',
216 'access arguments' => array('access birthdays'),
217 'type' => MENU_SUGGESTED_ITEM,
218 'file' => 'birthdays.page.inc',
219 );
220
221 return $items;
222 }
223
224 /**
225 * Implementation of hook_theme().
226 */
227 function birthdays_theme() {
228 return array(
229 'birthdays_block' => array(
230 'arguments' => array('uids' => array(), 'amount' => 0, 'block_type' => NULL),
231 'template' => 'birthdays-block',
232 ),
233 'birthdays_page' => array(
234 'arguments' => array('accounts' => array(), 'filter_month' => NULL, 'filter_year' => NULL),
235 'file' => 'birthdays.page.inc',
236 'template' => 'birthdays-page',
237 ),
238 );
239 }
240
241 /**
242 * Implementation of hook_perm().
243 */
244 function birthdays_perm() {
245 return array('access birthdays');
246 }
247
248
249 /**
250 * Implementation of hook_cron().
251 */
252 function birthdays_cron() {
253 global $_birthdays_field;
254
255 // Either user mail or admin mail is activated, and the birthdays profile field has been set.
256 if (isset($_birthdays_field) && (variable_get('birthdays_send_user', BIRTHDAYS_USER_MAIL_NO) != BIRTHDAYS_USER_MAIL_NO || variable_get('birthdays_remind', BIRTHDAYS_ADMIN_MAIL_DISABLED) != BIRTHDAYS_ADMIN_MAIL_DISABLED)) {
257 // Perform the check just once a day
258 $time = time();
259 if (variable_get('birthdays_last_cron', 0) <= ($time - 24*3600)) {
260 // The message functions are now necessary, lets include them.
261 module_load_include('inc', 'birthdays', 'birthdays.mail');
262 // Reset time limit, round to nearest 100 seconds.
263 variable_set('birthdays_last_cron', floor($time/100)*100);
264
265 $remind_frequency = variable_get('birthdays_remind', BIRTHDAYS_ADMIN_MAIL_DISABLED);
266
267 // Send user e-mails.
268 _birthdays_send_user_message();
269
270 // Send admin message if frequency is daily.
271 if ($remind_frequency == BIRTHDAYS_ADMIN_MAIL_DAILY) {
272 _birthdays_send_admin_message(1);
273 }// Send admin message if frequency is weekly and today is the first day of the week.
274 elseif ($remind_frequency == BIRTHDAYS_ADMIN_MAIL_WEEKLY && date('w', $time) == variable_get('date_first_day', 0)) {
275 _birthdays_send_admin_message(7);
276 }// Send admin message if frequency is monthly and today is the first day of the month.
277 elseif ($remind_frequency == BIRTHDAYS_ADMIN_MAIL_MONTHLY && date('j', $time) == 1) {
278 _birthdays_send_admin_message(date('t', $time));
279 }
280 }
281 }
282 }
283
284
285 /**
286 * Implementation of hook_block().
287 */
288 function birthdays_block($op = 'list', $delta = 'by_days', $edit = array()) {
289 global $_birthdays_field;
290 if (isset($_birthdays_field)) {
291 switch ($op) {
292 // List the blocks on the blocks settings page
293 case 'list':
294 $blocks['by_days']['info'] = t('Birthdays Block: Next N days');
295 $blocks['by_birthdays']['info'] = t('Birthdays Block: N upcoming birthdays');
296 return $blocks;
297
298 // Configure the blocks
299 case 'configure':
300 $form = array();
301 switch ($delta) {
302 case 'by_days':
303 $form["birthdays_block_settings"] = array(
304 '#type' => 'textfield',
305 '#title' => t("Number of days to show"),
306 '#default_value' => variable_get("birthdays_block_number_by_days", 7),
307 '#size' => 2,
308 '#maxlength' => 2,
309 '#description' => t("Number of days looking forward for upcoming birthdays. Use 1 for today's birthdays only. Note: it might show more or less birthday items than the specified number of days, because not all days have birthdays, and some days have multiple birthdays."),
310 '#required' => TRUE,
311 );
312 break;
313
314 case 'by_birthdays':
315 $form["birthdays_block_settings"] = array(
316 '#type' => 'textfield',
317 '#title' => t("Number of birthdays to show"),
318 '#default_value' => variable_get("birthdays_block_number_by_birthdays", 6),
319 '#size' => 2,
320 '#maxlength' => 2,
321 '#description' => t("Number of upcoming birthdays to list in the block. It will show exactly the specified number of birthdays, even if more people have their birthday on the same day. In that case, there will be people who will never be shown."),
322 '#required' => TRUE,
323 );
324 break;
325
326 }
327 $form['birthdays_block_hide'] = array(
328 '#type' => 'radios',
329 '#title' => t('Hide block when no birthdays'),
330 '#default_value' => variable_get("birthdays_block_hide_empty", 0),
331 '#options' => array(t('No'), t('Yes')),
332 '#description' => t("Should the block be hidden when there are no upcoming birthdays, or should it show a message."),
333 );
334
335 return $form;
336
337 // Save the block's configuration
338 case 'save':
339 variable_set('birthdays_block_number_'. $delta, $edit['birthdays_block_settings']);
340 variable_set('birthdays_block_hide_empty', $edit['birthdays_block_hide']);
341 return;
342
343 // View a block
344 case 'view':
345 $block = array();
346 // Nothing to show when birthday_field_name is still empty
347 // Don't show anything when the current user doesn't have the rights.
348 if (user_access('access birthdays')) {
349 switch ($delta) {
350 case 'by_days':
351 // Get desired amount of birthdays
352 $amount = variable_get("birthdays_block_number_by_days", 7);
353 $uids = birthdays_get_birthdays_by_days($amount);
354
355 if (count($uids) > 0 || variable_get('birthdays_block_hide_empty', 0) == 0) {
356 // Prepare block
357 $block['subject'] = t('Upcoming Birthdays');
358 $block['content'] = theme('birthdays_block', $uids, $amount, $delta);
359 }
360 break;
361 case 'by_birthdays':
362 // Get desired amount of birthdays
363 $amount = variable_get("birthdays_block_number_by_birthdays", 6);
364 $uids = birthdays_get_birthdays($amount);
365
366 if (count($uids) > 0 || variable_get('birthdays_block_hide_empty', 0) == 0) {
367 // Prepare block
368 $block['subject'] = t('Upcoming Birthdays');
369 $block['content'] = theme('birthdays_block', $uids, $amount, $delta);
370 }
371 break;
372 }
373
374 return $block;
375 }
376 }
377 }
378 }
379
380
381 /**
382 * Preprocess variables to format the birthdays block.
383 *
384 * $variables contains the following data:
385 * - $uids
386 * - $amount
387 * - $block_type
388 */
389 function template_preprocess_birthdays_block(&$variables) {
390 global $_birthdays_field;
391 //dsm($variables);
392 $variables['no_birthdays'] = TRUE;
393 $variables['show_starsigns'] = (bool) variable_get('birthdays_show_starsign',BIRTHDAYS_STARSIGN_OFF);
394
395 if (!empty($variables['uids'])) {
396 $row = 0;
397 $variables['no_birthdays'] = FALSE;
398
399 foreach ($variables['uids'] as $uid) {
400 $account = user_load(array('uid' => $uid));
401 $birthdays[$row]['account'] = $account;
402 $birthdays[$row]['username'] = theme('username', $account);
403
404 // +1 when the birthday isn't today, because it shows the age the person will be on his/her birthday
405 $account->age = ($account->age + !($account->{$_birthdays_field->name}['day'] == format_date(time(), 'custom', 'j') && $account->{$_birthdays_field->name}['month'] == format_date(time(), 'custom', 'n')));
406
407 $birthdays[$row]['age'] = _birthdays_show_age($account);
408 $birthdays[$row]['show_age'] = isset($birthdays[$row]['age']);
409
410 $birthdays[$row]['starsign'] = birthdays_get_starsign_image($account->birthdays_starsign, variable_get('birthdays_show_starsign',BIRTHDAYS_STARSIGN_OFF));
411
412 $account->{$_birthdays_field->name}['year'] = NULL; // Don't show the year in blocks
413 $birthdays[$row]['date'] = _birthdays_show_date($account->{$_birthdays_field->name}, $account);
414
415
416 $row++;
417 }
418 $variables['birthdays'] = $birthdays;
419 }
420
421 $variables['more'] = '<div class="more-link">'. l(t('more'), 'birthdays', array('attributes' => array('title' => t('Show all birthdays.')))) .'</div>';
422 }
423
424
425 /**
426 * Helper function for displaying only todays birthdays
427 * @return An array containing all user objects that have their birthday today
428 */
429 function birthdays_get_todays_birthdays() {
430 return birthdays_get_birthdays_by_days(1);
431 }
432
433
434 /**
435 * Get all birthdays of the upcomming X days
436 *
437 * @var $amount
438 * Integer stating the amount of days to look forward, including today.
439 * @return array
440 * An array containing user objects meeting the criteria
441 */
442 function birthdays_get_birthdays_by_days($amount) {
443 $birthdays = array();
444 // Current user, needed for timezone information
445 global $user;
446
447 // $amount should be larger or equal to 1
448 if ($amount < 1) {
449 $amount = 1;
450 }
451
452 // Get user time zone
453 // needed to determine what day 'today' is in the timezone of the user/website.
454 if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
455 $timezone = $user->timezone;
456 }
457 else { // else use timezone of Drupal installation
458 $timezone = variable_get('date_default_timezone', 0);
459 }
460
461 // MySQL prior to 4.1.1 has no option to use UTC, while drupal uses UTC.
462 // This is compensated by subtracting the machines timezone from the Drupal timezone.
463 // I believe the assumption is that the HTTP-server has the same timezone as the MySQL server.
464 $timezone -= date('Z');
465
466 // Hack to look further than the end of the year, if needed.
467 $current_year = date('Y');
468 $next_year = $current_year + 1;
469
470 /* Query:
471 - All dates are compensated for the timezone. This makes sure that someone in Asia will see the birthdays
472 of day 2 while someone in America still sees day 1.
473 - Blocked users are not shown
474 - Users that haven't logged in yet are also not shown (Drupal prohibits accessing their profile, thus showing
475 a link to the profile is unwanted). This is a anti spammers method.
476 - First part selects all birthdays that are in the next year when the interval exceeds the end of this year.
477 - Second part selects all birthdays that are between the begin and end date and are in the current year
478 */
479
480 switch ($GLOBALS['db_type']) {
481 case 'mysql':
482 case 'mysqli':
483 $result = db_query(
484 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
485 AND (
486 (
487 DATE_FORMAT({dob}.birthday,'$next_year%%m%%d') - DATE_FORMAT(ADDDATE(ADDDATE(NOW(),INTERVAL %d SECOND),INTERVAL %d DAY),'%%Y%%m%%d') < 0
488 )
489 OR
490 (
491 DATE_FORMAT({dob}.birthday,'$current_year%%m%%d') - DATE_FORMAT(ADDDATE(NOW(),INTERVAL %d SECOND),'%%Y%%m%%d') >= 0
492 AND
493 DATE_FORMAT({dob}.birthday,'$current_year%%m%%d') - DATE_FORMAT(ADDDATE(ADDDATE(NOW(),INTERVAL %d SECOND),INTERVAL %d DAY),'%%Y%%m%%d') < 0
494 ) )
495 ORDER BY MONTH({dob}.birthday), DAYOFMONTH({dob}.birthday), YEAR({dob}.birthday), {users}.name", $timezone, $amount, $timezone, $timezone, $amount
496 );
497 break;
498 case 'pgsql':
499 $result = db_query(
500 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
501 AND (
502 (
503 cast(to_char({dob}.birthday,'{$next_year}MMDD') as integer) - cast(to_char(current_timestamp + INTERVAL '%d seconds' + INTERVAL '%d days','YYYYMMDD') as integer) < 0
504 )
505 OR
506 (
507 cast(to_char({dob}.birthday,'{$current_year}MMDD') as integer) - cast(to_char(current_timestamp + INTERVAL '%d seconds','YYYYMMDD') as integer) >= 0
508 AND
509 cast(to_char({dob}.birthday,'{$current_year}MMDD') as integer) - cast(to_char(current_timestamp + INTERVAL '%d seconds' + INTERVAL '%d days','YYYYMMDD') as integer) < 0
510 ) )
511 ORDER BY date_part('month', {dob}.birthday), date_part('day', {dob}.birthday), date_part('year', {dob}.birthday), {users}.name", $timezone, $amount, $timezone, $timezone, $amount
512 );
513 break;
514 }
515
516 while ($account = db_fetch_object($result)) {
517 $birthdays[] = $account->uid;
518 }
519
520 // Return array of uids that have their birthday
521 return $birthdays;
522 }
523
524
525 /**
526 * Get the next X birthdays
527 *
528 * @var $amount
529 * Integer stating the amount of birthdays to retrieve.
530 * @return array
531 * An array containing user objects meeting the criteria
532 */
533 function birthdays_get_birthdays($amount) {
534 $birthdays = array();
535
536 // Current logged in user
537 global $user;
538
539 // Get user time zone
540 // Needed to determine what day 'today' is in the timezone of the user/website.
541 if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
542 $timezone = $user->timezone;
543 }
544 else {
545 $timezone = variable_get('date_default_timezone', 0);
546 }
547
548 // $amount should be larger or equal to 1
549 if ($amount < 1) {
550 $amount = 1;
551 }
552
553 // MySQL prior to 4.1.1 has no option to use UTC, while drupal uses UTC.
554 // This is compensated by subtracting the machines timezone from the Drupal timezone.
555 // I believe the assumption is that the HTTP-server has the same timezone as the MySQL server.
556 $timezone -= date('Z');
557
558 /* Query:
559 - Select all active users that have their birthday today or in the future (stops at 31-12)
560 - return at most $amount users
561 - Don't show blocked users
562 - Users that haven't logged in yet are also not shown (Drupal prohibits accessing their profile, thus showing
563 a link to the profile is unwanted). This is a anti spammers method.
564 */
565 switch ($GLOBALS['db_type']) {
566 case 'mysql':
567 case 'mysqli':
568 $result = db_query_range(
569 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
570 AND DATE_FORMAT({dob}.birthday,'%%c%%d') - DATE_FORMAT(ADDDATE(NOW(),INTERVAL %d SECOND),'%%c%%d') >= 0
571 ORDER BY MONTH({dob}.birthday), DAYOFMONTH({dob}.birthday), YEAR({dob}.birthday), {users}.name", $timezone, 0, $amount
572 );
573 break;
574 case 'pgsql':
575 $result = db_query_range(
576 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
577 AND cast(to_char({dob}.birthday,'FMMMDD') as integer) - cast(to_char(current_timestamp + INTERVAL '%d seconds','FMMMDD') as integer) >= 0
578 ORDER BY date_part('month', {dob}.birthday), date_part('day', {dob}.birthday), date_part('year', {dob}.birthday), {users}.name", $timezone, 0, $amount
579 );
580 break;
581 }
582 $count_rows = 0;
583 while ($account = db_fetch_object($result)) {
584 $birthdays[] = $account->uid;
585 $count_rows++;
586 }
587
588 // If less than $amount results returned, look for more after 31-12
589 // return at most the difference between the number already found and
590 if ($count_rows < $amount) {
591 switch ($GLOBALS['db_type']) {
592 case 'mysql':
593 case 'mysqli':
594 $result = db_query_range(
595 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
596 AND DATE_FORMAT({dob}.birthday,'%%c%%d') - DATE_FORMAT(ADDDATE(NOW(),INTERVAL %d SECOND),'%%c%%d') < 0
597 ORDER BY MONTH({dob}.birthday), DAYOFMONTH({dob}.birthday), YEAR({dob}.birthday), {users}.name", $timezone, 0, $amount - $count_rows
598 );
599 break;
600 case 'pgsql':
601 $result = db_query_range(
602 "SELECT {dob}.uid FROM {dob}, {users} WHERE {users}.uid = {dob}.uid AND {users}.status <> 0 AND {users}.access <> 0
603 AND cast(to_char({dob}.birthday,'FMMMDD') as integer) - cast(to_char(current_timestamp + INTERVAL '%d seconds','FMMMDD') as integer) < 0
604 ORDER BY date_part('month', {dob}.birthday), date_part('day', {dob}.birthday), date_part('year', {dob}.birthday), {users}.name", $timezone, 0, $amount - $count_rows
605 );
606 break;
607 }
608
609 while ($account = db_fetch_object($result)) {
610 $birthdays[] = $account->uid;
611 }
612 }
613
614 // Return array of uids that have their birthday
615 return $birthdays;
616 }
617
618
619 /**
620 * Implementation of hook_user().
621 */
622 function birthdays_user($op, &$edit, &$account, $category = NULL) {
623 global $_birthdays_field;
624 // Do nothing with user when _birthdays_field is not yet set
625 if (!isset($_birthdays_field)) {
626 return;
627 }
628 switch ($op) {
629 case 'load':
630 return birthdays_load_user($account);
631 case 'update':
632 case 'insert':
633 return birthdays_save_user($edit, $account, $category);
634 case 'form':
635 return birthdays_form_user($edit, $account, $category);
636 case 'register':
637 return birthdays_form_user($edit, $account, $category, TRUE);
638 case 'delete':
639 // Delete from {dob} table, other information is handled by profile.module and user.module
640 db_query('DELETE FROM {dob} WHERE uid = %d', $account->uid);
641 break;
642 }
643 }
644
645
646 /**
647 * Inject information on a user load.
648 *
649 * @param object $account
650 * User object passed by reference.
651 */
652 function birthdays_load_user(&$account) {
653 global $_birthdays_field;
654 // Pre-load birthday-information into $account
655 profile_load_profile($account);
656
657 // If it was set by the user
658 if ($account->{$_birthdays_field->name}) {
659 // Set the user's age
660 $account->age = _birthdays_get_age($account->{$_birthdays_field->name});
661 }
662 }
663
664
665 /**
666 * Inject information and save birthday when editing or adding a user.
667 */
668 function birthdays_save_user(&$edit, &$account, $category) {
669 global $_birthdays_field;
670
671 // Only continue when the field is present in the form results
672 if (!empty($_birthdays_field->name) && array_key_exists($_birthdays_field->name, $edit)) {
673 // Extract the date information
674 if (is_array($edit[$_birthdays_field->name])) {
675 extract($edit[$_birthdays_field->name]);
676 }
677
678 // Delete the old
679 db_query("DELETE FROM {dob} where uid = %d", $account->uid);
680
681 if ($day && $year && $month) {
682 // Set the starsign for the user.module to save in the {users}.data field
683 $edit['birthdays_starsign'] = _birthdays_get_starsign($day, $month);
684 // Insert the new
685 db_query("INSERT INTO {dob} (uid, birthday) VALUES (%d, '%d-%d-%d');", $account->uid, $year, $month, $day);
686 }
687 else {
688 $edit['birthdays_starsign'] = '';
689 unset($edit[$_birthdays_field->name]);
690 }
691 }
692 }
693
694 /**
695 * Alter the way the birthday is shown. This is fired after every module has filled the profile.
696 */
697 function birthdays_profile_alter(&$account) {
698 global $_birthdays_field;
699 // If the _birthdays_field hasn't been set yet, do not continue
700 if (!isset($_birthdays_field)) {
701 return;
702 }
703
704 // If the field existed, and is amongst the profile fields to be shown, it is save to continue
705 if (isset( $_birthdays_field ) && array_key_exists($_birthdays_field->category, $account->content) && array_key_exists($_birthdays_field->name, $account->content[$_birthdays_field->category])) {
706
707 // Do you have access to see birthdays?
708 if (user_access('access birthdays')) {
709 // Show starsign (will be hidden when needed)
710 $starsign = '<span class="birthdays-starsign">'.
711 birthdays_get_starsign_image($account->birthdays_starsign, variable_get('birthdays_show_starsign', BIRTHDAYS_STARSIGN_OFF)) .
712 '</span>&nbsp;&nbsp;&nbsp;';
713
714 // Show age (when allowed by user and administrator)
715 if (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_NO || (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_USER && $account->birthdays_user_hide_year != BIRTHDAYS_HIDE_YEAR_USER_YES)) {
716 $age = '&nbsp;&nbsp;&nbsp;<span class="birthdays-age">('. $account->age .')</span>';
717 }
718
719 // Alter the profile field setup by profile.module. Show medium format in stead of short format
720 $account->content[$_birthdays_field->category][$_birthdays_field->name]['#value'] = $starsign . _birthdays_show_date($account->{$_birthdays_field->name}, $account, 'medium') . $age ;
721
722 }
723 else {
724 // No access? Remove from profile to show
725 unset($account->content[$_birthdays_field->category][$_birthdays_field->name]);
726 }
727 }
728 }
729
730
731 /**
732 * Adds user options to the profile form which are saved in {users}.data and
733 * are loaded during a user_load().
734 * @return fields for the form
735 */
736 function birthdays_form_user($edit, $account, $category, $register = FALSE) {
737 global $_birthdays_field;
738
739 // If the called category is the category of the form field
740 if ($category == $_birthdays_field->category || ($_birthdays_field->register && $register)) {
741 // If the hiding of the year is a user option: show the option
742 if (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_USER) {
743 $form[$_birthdays_field->category]['birthdays_user_hide_year'] = array(
744 '#type' => 'checkbox',
745 '#title' => t("Hide age and birth year"),
746 '#default_value' => (int) $account->birthdays_user_hide_year,
747 '#description' => t("Do not show your age and your year of birth."),
748 '#return_value' => BIRTHDAYS_HIDE_YEAR_USER_YES,
749 '#weight' => $_birthdays_field->weight + 1
750 );
751 }
752
753 // If the birthday user mail is optionally, show the option
754 if (variable_get('birthdays_send_user', BIRTHDAYS_USER_MAIL_NO) == BIRTHDAYS_USER_MAIL_USER) {
755 $form[$_birthdays_field->category]['birthdays_user_send_mail'] = array(
756 '#type' => 'checkbox',
757 '#title' => t("Do not send birthday mail"),
758 '#default_value' => (int) $account->birthdays_user_send_mail,
759 '#description' => t("Do not send me an e-mail or e-card when it's my birthday."),
760 '#return_value' => BIRTHDAYS_USER_MAIL_USER_NO,
761 '#weight' => $_birthdays_field->weight + 1
762 );
763 }
764 }
765
766 return $form;
767 }
768
769 /**
770 * Implementation of hook_form_alter().
771 */
772 function birthdays_form_alter(&$form, &$form_state, $form_id) {
773 global $_birthdays_field;
774
775 if (($form_id == 'user_profile_form' && isset($form[$_birthdays_field->category])) || ($form_id == 'user_register' && $_birthdays_field->register)) {
776 $form[$_birthdays_field->category][$_birthdays_field->name]['#process'] = array('expand_birthdays_date');
777 $form[$_birthdays_field->category][$_birthdays_field->name]['#element_validate'] = array('birthdays_date_validate');
778 }
779 }
780
781 /**
782 * Process the birthday field (based on a regular date element) to
783 * limit it to past birthdays and make it the entire element optional
784 * by adding empty options for days, months and years.
785 */
786 function expand_birthdays_date($element) {
787 if (empty($element['#value'])) {
788 $element['#value'] = array('day' => '', 'month' => '', 'year' => '');
789 }
790
791 $element = expand_date($element);
792 $element['month']['#options'] = array('' => '--') + $element['month']['#options'];
793 $element['day']['#options'] = array('' => '--') + $element['day']['#options'];
794 $element['year']['#options'] = array('' => '--') + drupal_map_assoc(range(date('Y'), 1900));
795
796 return $element;
797 }
798
799 /**
800 * Validate the birthday field.
801 */
802 function birthdays_date_validate($element) {
803 extract($element['#value']);
804 if (empty($month) || empty($year) || empty($day)) {
805 if ($element['#required']) {
806 form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
807 }
808 elseif (!(empty($month) && empty($year) && empty($day))) {
809 form_error($element, t('The specified date is invalid.'));
810 }
811 }
812 elseif (!checkdate($month, $day, $year)) {
813 form_error($element, t('The specified date is invalid.'));
814 }
815 }
816
817 /**
818 * Get starsign based on date of birth
819 *
820 * @var $day and $month, decribing date of birth
821 * @return The name of the starsign
822 */
823 function _birthdays_get_starsign($day, $month) {
824
825 switch ($month) {
826 case 1:
827 $starsign = $day < 20 ? 'capricorn' : 'aquarius';
828 break;
829 case 2:
830 $starsign = $day < 19 ? 'aquarius' : 'pisces';
831 break;
832 case 3:
833 $starsign = $day < 21 ? 'pisces' : 'aries';
834 break;
835 case 4:
836 $starsign = $day < 20 ? 'aries' : 'taurus';
837 break;
838 case 5:
839 $starsign = $day < 21 ? 'taurus' : 'gemini';
840 break;
841 case 6:
842 $starsign = $day < 22 ? 'gemini' : 'cancer';
843 break;
844 case 7:
845 $starsign = $day < 23 ? 'cancer' : 'leo';
846 break;
847 case 8:
848 $starsign = $day < 23 ? 'leo' : 'virgo';
849 break;
850 case 9:
851 $starsign = $day < 23 ? 'virgo' : 'libra';
852 break;
853 case 10:
854 $starsign = $day < 23 ? 'libra' : 'scorpio';
855 break;
856 case 11:
857 $starsign = $day < 23 ? 'scorpio' : 'sagittarius';
858 break;
859 case 12:
860 $starsign = $day < 22 ? 'sagittarius' : 'capricorn';
861 break;
862 }
863
864 return $starsign;
865 }
866
867
868 /**
869 * Retrieve all fields of type 'date' from the profile.module's tables
870 * @return array with fieldnames
871 */
872 function _birthdays_get_date_fields() {
873 $options = array();
874 $result = db_query("SELECT fid, name FROM {profile_fields} WHERE type = 'date'");
875
876 while ($field = db_fetch_object($result)) {
877 $options[$field->fid] = $field->name;
878 }
879
880 return $options;
881 }
882
883
884 /**
885 * Retrieve profile field object
886 *
887 * @var string $fid
888 * Id of field to retrieve
889 * @return object
890 * profile field object
891 */
892 function _birthdays_get_field($fid) {
893 if (isset($fid)) {
894 $field = db_fetch_object(db_query("SELECT * FROM {profile_fields} WHERE fid = %d", $fid));
895 return empty($field) ? NULL : $field;
896 }
897 else {
898 return NULL;
899 }
900 }
901
902
903 /**
904 * Return the picture of a starsign, given the name. Links to Yahoo! when option is selected.
905 *
906 * @param string starsign
907 * name of the starsign to show (not translated)
908 * @param int $show
909 * Show starsigns for values > 0
910 * @return string
911 * HTML of a picture link to Yahoo horoscopes
912 */
913 function birthdays_get_starsign_image($starsign, $show = BIRTHDAYS_STARSIGN_OFF) {
914 $output = '';
915
916 // Only show starsign when enabled
917 if ($show > BIRTHDAYS_STARSIGN_OFF && !empty($starsign)) {
918 // Image based on thme path.
919 $output = '<img src="'. base_path() . drupal_get_path('module', 'birthdays') .'/starsigns/'. $starsign .'.gif" alt="'. t($starsign) .'" />';
920
921 // If link should be shown: update $output
922 if ($show == BIRTHDAYS_STARSIGN_LINK) {
923 $output = '<a href="http://astrology.yahoo.com/astrology/general/dailyoverview/'. $starsign .'" target="_blank" title="'. t($starsign) .'">'. $output .'</a>';
924 }
925 }
926
927 // Return HTML
928 return $output;
929 }
930
931 /**
932 * Get age from a given date of birth
933 *
934 * @var array $date
935 * array containing fields with keys 'year', 'month' and 'day'
936 * @return int
937 * age
938 */
939 function _birthdays_get_age($date) {
940 // If date is not empty
941 if (is_array($date)) {
942 // extract date
943 extract($date);
944
945 // call main age function (no overloading in PHP)
946 return _birthdays_calculate_age($day, $month, $year);
947 }
948 else {
949 return NULL;
950 }
951 }
952
953
954 /**
955 * Calculate age
956 *
957 * @var $year, $month, $day as expected
958 * @return int
959 * age
960 */
961 function _birthdays_calculate_age($day, $month, $year) {
962 if ($year && $month && $day) {
963 // age = (current year - birthyear) - 1 (when the birthday hasn't arrived yet).
964 return format_date(time(), 'custom', 'Y') - $year - (format_date(time(), 'custom', 'nd') < $month . str_pad($day, 2, 0, STR_PAD_LEFT));
965 }
966 else {
967 return NULL;
968 }
969 }
970
971
972 /**
973 * Return age if user has agreed to show it
974 *
975 * @param object $account
976 * a user object having attribute "age" set
977 * @return int
978 */
979 function _birthdays_show_age($account) {
980 $age = NULL;
981 if (isset($account->age) && (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_NO || (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_USER && $account->birthdays_user_hide_year != BIRTHDAYS_HIDE_YEAR_USER_YES))) {
982 $age = $account->age;
983 }
984 return $age;
985 }
986
987
988 /**
989 * Format date array
990 */
991 function _birthdays_show_date($date, $account, $format = 'small') {
992 if (is_array($date)) {
993 // Extract date
994 extract($date);
995
996 // Call main format function
997 return _birthdays_show_date_2($day, $month, $year, $account, $format);
998 }
999 else {
1000 return NULL;
1001 }
1002 }
1003
1004 /**
1005 * Format date, optionally hide year
1006 */
1007 function _birthdays_show_date_2($day, $month, $year, $account, $type = 'small') {
1008 $output = '';
1009 // Determine format type
1010 switch ($type) {
1011 case 'medium':
1012 $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
1013 break;
1014 case 'small':
1015 default:
1016 $format = variable_get('date_format_short', 'm/d/Y - H:i');
1017 }
1018
1019 // remove time from (- H:i)
1020 //$format = substr($format, 0, -6);
1021
1022 // If admin or user decide to hide the age&year: hide year
1023 if ($year && ( variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_YES || (variable_get('birthdays_hide_year', BIRTHDAYS_HIDE_YEAR_NO) == BIRTHDAYS_HIDE_YEAR_USER && $account->birthdays_user_hide_year == BIRTHDAYS_HIDE_YEAR_YES))) {
1024 $year = NULL;
1025 }
1026
1027 // Replacement array (can't use date() because of 1970 limitations in e.g. Windows PHP4)
1028 $replace = array(
1029 'd' => sprintf('%02d', $day),
1030 'D' => NULL,
1031 'j' => $day,
1032 'm' => sprintf('%02d', $month),
1033 'M' => map_month($month),
1034 'Y' => $year,
1035 'H:i' => NULL,
1036 'G:i' => NULL,
1037 'g:ia' => NULL,
1038 'F' => t(gmdate('F', mktime(0, 0, 0, $month, 15, 2000))),
1039 );
1040
1041 // Translate string to correct format
1042 $output .= strtr($format, $replace);
1043 $output = trim($output, '/ ,.:-');
1044
1045 return $output;
1046 }
1047
1048 /**
1049 * Check which e-mail strings should be retreived, and fill in the default
1050 * placeholders. Uses the same method as _user_mail_text().
1051 */
1052 function _birthdays_mail_text($key, $language = NULL, $variables = array()) {
1053 $langcode = isset($language) ? $language->language : NULL;
1054
1055 // If the text is not the default, run it through strtr() to fill in the
1056 // placeholders.
1057 if ($text = variable_get('birthdays_send_user_' . $key, FALSE)) {
1058 return strtr($text, $variables);
1059 }
1060 else {
1061 // Which text do we want to retreive?
1062 switch ($key) {
1063 case 'subject':
1064 return t('Happy Birthday, !username!', $variables, $langcode);
1065 case 'message':
1066 return t("Hey !username,\n\nHappy birthday!\nWe hope you have a great day\n\nThe !site-team\n!uri_brief", $variables, $langcode);
1067 }
1068 }
1069 }

  ViewVC Help
Powered by ViewVC 1.1.2