notifications.module

Tracking 7.x-1.x branch
  1. drupal
    1. 6 contributions/notifications/notifications.module
    2. 7 contributions/notifications/notifications.module

Notifications module

This is the base module of the notifications framework. It handles event processing, queueing, message composition and sending.

Different subscriptions types are provided by plug-in modules implementing hook_notifications() Most of the UI is implemented in notifications_ui module The messaging framework is used for message delivery Token module is used for token replacement in messages

Hidden variables (can be set programatically, have no UI):

  • 'notifications_event_log', number of seconds logs will be kept (defaults to 7 days) To keep logs longer than a week, define the (hidden) variable
  • 'notifications_event_dispatch', dispatch events, defaults to 1 Set to 0 to disable event dispatching (no new notifications will be queued nor sent)

This is based on the previous subscriptions module

Development Seed, http://www.developmentseed.org, 2007

Functions & methods

NameDescription
notifications_access_anonymousCheck access for anonymous subscriptions
notifications_access_subscribeMenu access callback for subscribe links.
notifications_access_subscriptionMenu access callback. Access subscription forms for given subscription
notifications_access_unsubscribeMenu access callback for unsubscribe links.
notifications_access_userMenu access callback for user subscriptions
notifications_access_user_addMenu access callback, add a given subscription type
notifications_array_filterFilter elements in an array of arrays/objects that match some condition
notifications_array_serializeSerialize an array ordering the keys before.
notifications_build_methodInformation about digesting method for a send interval.
notifications_check_signatureCheck signature from URL and query string
notifications_cronImplementation of hook_cron()
notifications_cron_queue_event_workerWorker callback. Check whether the message has expired before sending out.
notifications_cron_queue_infoImplementation of hook_cron_queue_info()
notifications_delete_destinationShorthand function for deleting everything related to a destination
notifications_destination_accessMenu access callback for destinations
notifications_entity_infoImplements hook_entity_info().
notifications_eventCreate event object of given type
notifications_event_enabledCheck whether we have enabled events of this type
notifications_event_enabled_typesGet event types. Invoking this function will also load the event API
notifications_event_typeGet information about event types. Invoking this function will also load the event API
notifications_field_typeGet information about subscriptions fields
notifications_format_itemsFormat items according to predefined formats
notifications_format_title_descriptionArray item callback to format title and description
notifications_formsImplementation of hook_forms()
notifications_get_subscriptionsLoad multiple subscriptions.
notifications_get_subscriptions_not_nullFilter callback.
notifications_helpImplements hook_help().
notifications_infoInvoke hook_notifications($name) on all modules and get a property from the array
notifications_menuImplementation of hook_menu().
notifications_messagingImplementation of hook_messaging()
notifications_messaging_methodImplements hook_messaging_method()
notifications_notificationsImplementation of hook_notifications()
notifications_notifications_subscription_listImplementation of hook_notifications_subscription_list().
notifications_objectCreate a wrapped object and keep a static cache of created objects.
notifications_object_typeGet info about object types
notifications_option_array_getGet an array of options indexed by type
notifications_option_array_setSet the same property for a family of array variables
notifications_option_getGet value from notifications_option_* variables
notifications_option_setSet value from notifications_option_* variables
notifications_permissionImplementation of hook_permission()
notifications_save_subscriptionUpdate or create subscription
notifications_send_intervalsList of send intervals, only Immediately if no advanced queue enabled
notifications_send_methodsGet list of send methods for user or anonymous account
notifications_subscriptionBuild subscription type object. We keep an object for each type so we can quickly clone it
notifications_subscription_buildBuild subscription object properly
notifications_subscription_enabled_typesGet enabled subscription types
notifications_subscription_formSubscription form ('add', 'edit', 'confirm')
notifications_subscription_form_submitProcess form submission
notifications_subscription_form_validateValidate form submission
notifications_subscription_listBuild a subscriptions list collection with this name
notifications_subscription_list_formForm with subscription list
notifications_subscription_list_form_submitProcess list form submission
notifications_subscription_list_form_validateValidate list form submission
notifications_subscription_loadMenu loading, subscription
notifications_subscription_typeGet info about subscription types
notifications_subscription_type_enabledCheck if this type is enabled or get array with all enabled types
notifications_subscription_type_loadLoad subscription type for menu operations
notifications_subscription_user_typesGet subscription type objects available for a user or current user
notifications_subscritpion_type_listGet list of subscription type names
notifications_templateCreate notifications template object
notifications_template_infoGet info about templates
notifications_themeImplementation of hook_theme()
notifications_tokensImplements hook_tokens().
notifications_token_infoImplements hook_token_info().
notifications_url_optionsWrapper for url() function with some more options
notifications_url_signatureSignature for url parameters
notifications_userImplementation of hook_user().
notifications_user_deleteImplementation of hook_user().
notifications_user_settingGets a user setting, defaults to default system setting for each
_notifications_send_methodsList of send methods

Constants

NameDescription
NOTIFICATIONS_EVENT_LOG
NOTIFICATIONS_FORMAT_HTML
NOTIFICATIONS_FORMAT_INLINE
NOTIFICATIONS_FORMAT_LIST
NOTIFICATIONS_FORMAT_PLAIN
NOTIFICATIONS_FORMAT_TABLE

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * Notifications module
  5. *
  6. * This is the base module of the notifications framework. It handles event processing, queueing,
  7. * message composition and sending.
  8. *
  9. * Different subscriptions types are provided by plug-in modules implementing hook_notifications()
  10. * Most of the UI is implemented in notifications_ui module
  11. * The messaging framework is used for message delivery
  12. * Token module is used for token replacement in messages
  13. *
  14. * Hidden variables (can be set programatically, have no UI):
  15. *
  16. * - 'notifications_event_log', number of seconds logs will be kept (defaults to 7 days)
  17. * To keep logs longer than a week, define the (hidden) variable
  18. *
  19. * - 'notifications_event_dispatch', dispatch events, defaults to 1
  20. * Set to 0 to disable event dispatching (no new notifications will be queued nor sent)
  21. *
  22. * This is based on the previous subscriptions module
  23. *
  24. * Development Seed, http://www.developmentseed.org, 2007
  25. */
  26. // Format as plaintext. Note it evaluates to false.
  27. define('NOTIFICATIONS_FORMAT_PLAIN', 0);
  28. // Format as html. Note it evaluates to true
  29. define('NOTIFICATIONS_FORMAT_HTML', 1);
  30. // Format inline, as a string of csv
  31. define('NOTIFICATIONS_FORMAT_INLINE', 2);
  32. // Format as HTML table (4 +1)
  33. define('NOTIFICATIONS_FORMAT_TABLE', 5);
  34. // Format as item list (8 + 2(inline) + 1 (html))
  35. define('NOTIFICATIONS_FORMAT_LIST', 10);
  36. // Default time for logs, 7 days
  37. define('NOTIFICATIONS_EVENT_LOG', 7* 24 * 3600);
  38. /**
  39. * Implements hook_help().
  40. *
  41. * This file will be included only for Notifications admin pages
  42. */
  43. function notifications_help($path, $arg) {
  44. $pages = array(
  45. '@admin-events' => url( 'admin/config/messaging/notifications/events'),
  46. '@admin-subscriptions' => url('admin/config/messaging/subscriptions'),
  47. '@admin-messaging' => url('admin/config/messaging/settings'),
  48. '@admin-methods' => url('admin/config/messaging/settings/methods'),
  49. '@admin-triggers' => url('admin/structure/trigger'),
  50. );
  51. switch ($path) {
  52. case 'admin/config/messaging/notifications/events':
  53. $output = '<p>' . t('To set up event actions, go to the <a href="@admin-triggers">Triggers page</a>.', $pages) . '</p>';
  54. return $output;
  55. case 'admin/config/messaging/notifications/settings':
  56. // Try to clarify some concepts, tell the long story short.
  57. $output = '<p>' . t('Users can subscribe to different objects (nodes, users, tags) by creating <strong><a href="@admin-subscriptions">Subscriptions</a></strong> for that objects. The subscription types available and the options to display will depend on additional modules enabled.', $pages) . '</p>';
  58. $output .= '<p>' . t('When an <a href="@admin-events">Event</a> happens (node update, comment) and it matches an existing subscription, that triggers a <strong>Notification</strong> which is a <strong>Message</strong> that will be sent to the user through one of the available <a href="@admin-methods">Sending Methods</a>.', $pages) . '</p>';
  59. $output .= '<p>' . t('These <strong>Notifications</strong> can be sent right away or queued to be processed on <i>cron</i>. Optionally Notifications can be digested and sent out every some <a href="@admin-intervals">time interval</a>.', $pages) . '</p>';
  60. return $output;
  61. case 'admin/messaging/notifications/subscriptions':
  62. $output = '<p>' . t('On this page you can define which subscription types are enabled or disabled. <strong>Disabled subscription types will not be available for users</strong>.') . '</p>';
  63. $output .= '<p>' . t('<strong>Existing subscriptions will be updated accordingly</strong>. They\'ll be disabled when their type is disabled or re-enabled when they were disabled and the type is enabled.') . '</p>';
  64. return $output;
  65. }
  66. }
  67. /**
  68. * Format items according to predefined formats
  69. */
  70. function notifications_format_items($items, $format = NOTIFICATIONS_FORMAT_LIST) {
  71. if (!($format & NOTIFICATIONS_FORMAT_HTML)) {
  72. $items = array_map('check_plain', $items);
  73. }
  74. if ($format & NOTIFICATIONS_FORMAT_LIST) {
  75. return theme('item_list', $items);
  76. }
  77. elseif ($format & NOTIFICATIONS_FORMAT_TABLE) {
  78. // @todo Return as table row ?
  79. }
  80. elseif ($format & NOTIFICATIONS_FORMAT_INLINE) {
  81. return implode(', ', $items);
  82. }
  83. else {
  84. return $items;
  85. }
  86. }
  87. /**
  88. * Implementation of hook_menu().
  89. */
  90. function notifications_menu() {
  91. $items['admin/config/messaging/notifications'] = array(
  92. 'title' => 'Notifications settings',
  93. 'description' => 'Configure notifications.',
  94. 'page callback' => 'drupal_get_form',
  95. 'page arguments' => array('notifications_settings_form'),
  96. 'access arguments' => array('administer site configuration'),
  97. 'file' => 'notifications.admin.inc',
  98. );
  99. $items['admin/config/messaging/notifications/settings'] = array(
  100. 'title' => 'Options',
  101. 'description' => 'Configure notifications',
  102. 'weight' => -10,
  103. 'type' => MENU_DEFAULT_LOCAL_TASK,
  104. );
  105. $items['admin/config/messaging/notifications/events'] = array(
  106. 'title' => 'Events',
  107. 'page callback' => 'drupal_get_form',
  108. 'page arguments' => array('notifications_admin_events_form'),
  109. 'type' => MENU_LOCAL_TASK,
  110. 'access arguments' => array('administer site configuration'),
  111. 'file' => 'notifications.admin.inc',
  112. );
  113. $items['admin/config/messaging/subscriptions'] = array(
  114. 'title' => 'Subscriptions settings',
  115. 'description' => 'Configure subscription types and options.',
  116. 'page callback' => 'drupal_get_form',
  117. 'page arguments' => array('notifications_admin_subscriptions_settings'),
  118. 'access arguments' => array('administer site configuration'),
  119. 'file' => 'notifications.admin.inc',
  120. );
  121. $items['admin/config/messaging/subscriptions/types'] = array(
  122. 'title' => 'Options',
  123. 'description' => 'Subscription options.',
  124. 'type' => MENU_DEFAULT_LOCAL_TASK,
  125. 'weight' => -10,
  126. );
  127. // Manage existing subscriptions
  128. $items['admin/notifications'] = array(
  129. 'title' => 'Subscriptions',
  130. 'description' => 'Manage existing subscriptions.',
  131. 'page callback' => 'drupal_get_form',
  132. 'page arguments' => array('notifications_admin_manage_subscriptions'),
  133. 'access arguments' => array('administer notifications'),
  134. 'file' => 'notifications.admin.inc',
  135. );
  136. $items['admin/notifications/admin'] = array(
  137. 'title' => 'Administer subscriptions',
  138. 'description' => 'Administer subscriptions.',
  139. 'type' => MENU_DEFAULT_LOCAL_TASK,
  140. 'access arguments' => array('administer notifications'),
  141. );
  142. /* @todo d7update
  143. $items['admin/notifications/status'] = array(
  144. 'title' => 'Status',
  145. 'description' => 'Summary of existing subscriptions.',
  146. 'page callback' => 'notifications_admin_status_page',
  147. 'access arguments' => array('administer notifications'),
  148. 'file' => 'notifications.admin.inc',
  149. 'type' => MENU_LOCAL_TASK,
  150. );
  151. */
  152. // Subscribe links. For this items access will be checked later in the page
  153. $items['notifications/subscribe/%notifications_subscription_type'] = array(
  154. 'title' => 'Subscribe',
  155. 'type' => MENU_CALLBACK,
  156. 'page callback' => 'notifications_page_subscribe',
  157. 'page arguments' => array(2),
  158. 'access callback' => 'notifications_access_subscribe',
  159. 'access arguments' => array(2),
  160. 'file' => 'notifications.pages.inc',
  161. );
  162. // Unsubscribe links This page will need to work with anonymous users
  163. // The parameter will be a list of sids, separated by commas
  164. $items['notifications/unsubscribe'] = array(
  165. 'title' => 'Unsubscribe',
  166. 'type' => MENU_CALLBACK,
  167. 'page callback' => 'notifications_page_unsubscribe_overview',
  168. 'access callback' => 'notifications_access_unsubscribe',
  169. 'file' => 'notifications.pages.inc',
  170. );
  171. // Unsubscribe links This page will need to work with anonymous users
  172. // The parameter will be a list of sids, separated by commas
  173. $items['notifications/unsubscribe/%notifications_subscription'] = array(
  174. 'title' => 'Unsubscribe',
  175. 'type' => MENU_CALLBACK,
  176. 'page callback' => 'notifications_page_unsubscribe_subscription',
  177. 'page arguments' => array(2),
  178. 'access callback' => 'notifications_access_unsubscribe',
  179. 'access arguments' => array(2),
  180. 'file' => 'notifications.pages.inc',
  181. );
  182. // Delete all subscriptions for user
  183. $items['notifications/unsubscribe/user/%user'] = array(
  184. 'title' => 'Unsubscribe',
  185. 'type' => MENU_CALLBACK,
  186. 'page callback' => 'notifications_page_unsubscribe_user',
  187. 'page arguments' => array(3),
  188. 'access callback' => 'notifications_access_unsubscribe',
  189. 'access arguments' => array(NULL, 3),
  190. 'file' => 'notifications.pages.inc',
  191. );
  192. // Edit subscription, stand alone page
  193. $items['notifications/subscription/%notifications_subscription'] = array(
  194. 'type' => MENU_CALLBACK,
  195. 'title' => 'Subscription',
  196. 'page callback' => 'drupal_get_form',
  197. 'page arguments' => array('notifications_subscription_form', 'view', 2),
  198. 'access callback' => 'notifications_access_subscription',
  199. 'access arguments' => array(2, 'view'),
  200. 'file' => 'notifications.pages.inc',
  201. );
  202. $items['notifications/subscription/%notifications_subscription/view'] = array(
  203. 'title' => 'Subscription',
  204. 'type' => MENU_DEFAULT_LOCAL_TASK,
  205. 'weight' => -10,
  206. );
  207. // Edit subscription, stand alone page
  208. $items['notifications/subscription/%notifications_subscription/edit'] = array(
  209. 'type' => MENU_LOCAL_TASK,
  210. 'title' => 'Edit',
  211. 'page callback' => 'drupal_get_form',
  212. 'page arguments' => array('notifications_subscription_form', 'edit', 2),
  213. 'access callback' => 'notifications_access_subscription',
  214. 'access arguments' => array(2, 'edit'),
  215. 'file' => 'notifications.pages.inc',
  216. );
  217. $items['notifications/subscription/%notifications_subscription/delete'] = array(
  218. 'type' => MENU_LOCAL_TASK,
  219. 'title' => 'Delete',
  220. 'weight' => 100,
  221. 'page callback' => 'drupal_get_form',
  222. 'page arguments' => array('notifications_subscription_form', 'delete', 2),
  223. 'access callback' => 'notifications_access_subscription',
  224. 'access arguments' => array(2, 'delete'),
  225. 'file' => 'notifications.pages.inc',
  226. );
  227. // Some autocomplete callbacks
  228. $items['notifications/autocomplete/node/title'] = array(
  229. 'title' => 'Node title autocomplete',
  230. 'page callback' => 'notifications_node_autocomplete_title',
  231. 'access arguments' => array('access content'),
  232. 'type' => MENU_CALLBACK,
  233. 'file' => 'includes/node.inc',
  234. );
  235. // Some autocomplete callbacks
  236. $items['notifications/autocomplete/node/type'] = array(
  237. 'title' => 'Node title autocomplete',
  238. 'page callback' => 'notifications_node_autocomplete_type',
  239. 'access arguments' => array('access content'),
  240. 'type' => MENU_CALLBACK,
  241. 'file' => 'includes/node.inc',
  242. );
  243. return $items;
  244. }
  245. /**
  246. * Menu access callback for subscribe links.
  247. *
  248. * More access checking depending on subscription type will be done at the destination page
  249. */
  250. function notifications_access_subscribe($substype, $account = NULL) {
  251. if ($substype && notifications_subscription_type_enabled($substype->type)) {
  252. $account = $account ? $account : $GLOBALS['user'];
  253. if ($account->uid) {
  254. return user_access('create subscriptions', $account);
  255. }
  256. elseif (notifications_check_signature()) {
  257. return TRUE; // Signed link
  258. }
  259. }
  260. }
  261. /**
  262. * Menu access callback for unsubscribe links.
  263. */
  264. function notifications_access_unsubscribe($subscription = NULL, $account = NULL) {
  265. if (notifications_check_signature()) {
  266. return TRUE; // Signed link
  267. }
  268. elseif ($subscription && $GLOBALS['user']->uid && $subscription->uid == $GLOBALS['user']->uid
  269. || $account && $GLOBALS['user']->uid == $account->uid) {
  270. return user_access('maintain own subscriptions');
  271. }
  272. elseif (!$subscription && !$account) {
  273. return user_access('maintain own subscriptions');
  274. }
  275. }
  276. /**
  277. * Menu access callback. Access subscription forms for given subscription
  278. */
  279. function notifications_access_subscription($subscription, $op = 'view', $account = NULL) {
  280. $account = $account ? $account : $GLOBALS['user'];
  281. if (user_access('administer notifications') || user_access('manage all subscriptions')) {
  282. return TRUE;
  283. }
  284. switch ($op) {
  285. case 'view':
  286. return $subscription->uid && ($subscription->uid == $account->uid);
  287. case 'edit':
  288. case 'unsubscribe':
  289. return $subscription->uid && ($subscription->uid == $account->uid) && user_access('maintain own subscriptions');
  290. }
  291. return FALSE;
  292. }
  293. /**
  294. * Menu access callback for user subscriptions
  295. *
  296. * @param $account
  297. * User account to which these subscriptions below
  298. * @param $op
  299. * - maintain = create / delete
  300. * - manage = use the per account administration page
  301. */
  302. function notifications_access_user($account, $op = 'maintain') {
  303. global $user;
  304. if (user_access('administer notifications') || user_access('manage all subscriptions')) {
  305. return TRUE;
  306. }
  307. else {
  308. return $account->uid && $user->uid == $account->uid &&
  309. (($op == 'maintain' && user_access('maintain own subscriptions')) || ($op == 'manage' && user_access('manage own subscriptions')));
  310. }
  311. }
  312. /**
  313. * Menu access callback, add a given subscription type
  314. */
  315. function notifications_access_user_add($account = NULL, $type = NULL) {
  316. global $user;
  317. $account = $account ? $account : $user;
  318. if (notifications_access_user($account)) {
  319. if ($type) {
  320. return notifications_subscription($type)->user_access($account);
  321. }
  322. else {
  323. return TRUE;
  324. }
  325. }
  326. }
  327. /**
  328. * Check signature from URL and query string
  329. */
  330. function notifications_check_signature($option = 'result') {
  331. $page_checked = &drupal_static(__FUNCTION__);
  332. if (!isset($page_checked)) {
  333. $page_checked = array(
  334. 'signed' => NULL,
  335. 'result' => NULL,
  336. 'timestamp' => 0,
  337. 'skip' => FALSE,
  338. );
  339. if (!empty($_GET['signature'])) {
  340. $page_checked['signed'] = FALSE;
  341. $query = $_GET;
  342. $signature = $query['signature'];
  343. unset($query['signature']);
  344. unset($query['q']); // Trim out the path element
  345. $path = current_path();
  346. if ($signature === notifications_url_signature($path, $query)) {
  347. $paget_checked['signed'] = TRUE;
  348. // Now check timestamp, it should be < 7 days
  349. if (!empty($query['timestamp']) && time() - 24 * 7 * 3600 > (int)$query['timestamp']) {
  350. drupal_set_message(t('This link has expired. Please get a new one or contact the site administrator.'), 'error');
  351. $page_checked['result'] = FALSE;
  352. }
  353. else {
  354. // Signature is ok and timestamp is ok or we don't have one.
  355. // (If you sign links that never expire, that's your problem.)
  356. $page_checked['timestamp'] = isset($query['timestamp']) ? (int)$query['timestamp'] : 0;
  357. $page_checked['result'] = TRUE;
  358. $page_checked['skip'] = !empty($query['skip']);
  359. }
  360. }
  361. else {
  362. drupal_set_message(t('This link is not valid anymore. Please get a new one or contact the site administrator.'), 'error');
  363. return $page_checked['result'] = FALSE;
  364. }
  365. }
  366. }
  367. // Return nothing, we didn't have any signature
  368. return $option ? $page_checked[$option] : $page_checked;
  369. }
  370. /**
  371. * Check access for anonymous subscriptions
  372. */
  373. function notifications_access_anonymous() {
  374. static $access;
  375. if (!isset($access)) {
  376. $access = module_exists('notifications_anonymous') && notifications_anonymous_send_methods() && notifications_anonymous_send_intervals();
  377. }
  378. return $access;
  379. }
  380. /**
  381. * Menu loading, subscription
  382. */
  383. function notifications_subscription_load($sid) {
  384. return Notifications_Subscription::load($sid);
  385. }
  386. /**
  387. * Menu access callback for destinations
  388. */
  389. function notifications_destination_access($op, $destination) {
  390. // Access will be granted only to administrator for now
  391. return user_access('administer notifications');
  392. }
  393. /**
  394. * Implements hook_entity_info().
  395. */
  396. function notifications_entity_info() {
  397. // Notifications_Event
  398. $info['notifications_event'] = array(
  399. 'label' => t('Event'),
  400. 'controller class' => 'MessagingEntityController',
  401. 'base class' => 'Notifications_Event',
  402. 'base table' => 'notifications_event',
  403. 'entity keys' => array(
  404. 'id' => 'eid',
  405. ),
  406. );
  407. // Notifications_Subscription
  408. $info['notifications_subscription'] = array(
  409. 'label' => t('Subscription'),
  410. 'controller class' => 'MessagingEntityController',
  411. 'base class' => 'Notifications_Subscription',
  412. 'base table' => 'notifications_subscription',
  413. 'uri callback' => 'notifications_subscription_uri',
  414. 'entity keys' => array(
  415. 'id' => 'sid',
  416. ),
  417. 'bundle keys' => array(
  418. 'bundle' => 'sid',
  419. ),
  420. 'bundles' => array(),
  421. 'view modes' => array(
  422. // @todo View mode for display as a field (when attached to nodes etc).
  423. 'full' => array(
  424. 'label' => t('Subscriptions page'),
  425. 'custom settings' => FALSE,
  426. ),
  427. ),
  428. );
  429. return $info;
  430. }
  431. /**
  432. * Implementation of hook_cron_queue_info()
  433. */
  434. /*
  435. function notifications_cron_queue_info() {
  436. $queues['notifications_queue'] = array(
  437. 'worker callback' => 'notifications_queue_cron_run',
  438. 'time' => 60,
  439. );
  440. return $queues;
  441. }
  442. */
  443. /**
  444. * Implementation of hook_notifications()
  445. */
  446. function notifications_notifications($op) {
  447. switch ($op) {
  448. case 'object types':
  449. $types['node'] = array(
  450. 'title' => t('Node'),
  451. 'class' => 'Notifications_Node',
  452. );
  453. $types['user'] = array(
  454. 'title' => t('User'),
  455. 'class' => 'Notifications_User',
  456. );
  457. return $types;
  458. case 'field types':
  459. // Information about available fields for subscriptions
  460. $fields['node:nid'] = array(
  461. 'title' => t('Node'),
  462. 'class' => 'Notifications_Node_Field',
  463. );
  464. $fields['user:uid'] = array(
  465. 'title' => t('User'),
  466. 'class' => 'Notifications_User_Field',
  467. );
  468. return $fields;
  469. }
  470. }
  471. /**
  472. * Get information about event types. Invoking this function will also load the event API
  473. *
  474. * @param $typekey
  475. * Event type key
  476. * @param $property
  477. * Property to return
  478. */
  479. function notifications_event_type($typekey = NULL, $property = NULL, $default = NULL) {
  480. return notifications_info('event types', $typekey, $property, $default);
  481. }
  482. /**
  483. * Get info about object types
  484. *
  485. * @param $type
  486. * String, the subscriptions type OPTIONAL
  487. * @param $field
  488. * String, a specific field to retrieve info from OPTIONAL
  489. *
  490. * Information for a given field and type
  491. * or information for a given field for all types
  492. */
  493. function notifications_object_type($type = NULL, $field = NULL, $default = NULL) {
  494. return notifications_info('object types', $type, $field, $default);
  495. }
  496. /**
  497. * Get info about subscription types
  498. *
  499. * @param $type
  500. * String, the subscriptions type OPTIONAL
  501. * @param $property
  502. * String, a specific property to retrieve info from OPTIONAL
  503. */
  504. function notifications_subscription_type($type = NULL, $property = NULL, $default = NULL) {
  505. return notifications_info('subscription types', $type, $property, $default);
  506. }
  507. /**
  508. * Get list of subscription type names
  509. *
  510. * @todo Filter by user account permissions
  511. */
  512. function notifications_subscritpion_type_list($account = NULL) {
  513. $list = notifications_subscription_type(NULL, 'title');
  514. return $list;
  515. }
  516. /**
  517. * Load subscription type for menu operations
  518. */
  519. function notifications_subscription_type_load($type) {
  520. return notifications_subscription($type);
  521. }
  522. /**
  523. * Get subscription type objects available for a user or current user
  524. */
  525. function notifications_subscription_user_types($account = NULL) {
  526. $account = $account ? $account : $GLOBALS['user'];
  527. $types = array();
  528. foreach (notifications_subscription_enabled_types() as $type => $substype) {
  529. if ($substype->user_access($account, 'subscribe')) {
  530. $types[$type] = $substype;
  531. }
  532. }
  533. return $types;
  534. }
  535. /**
  536. * Build subscription type object. We keep an object for each type so we can quickly clone it
  537. */
  538. function notifications_subscription($type) {
  539. $subscription_types = &drupal_static(__FUNCTION__);
  540. if (!isset($subscription_types[$type])) {
  541. $subscription_types[$type] = Notifications_Subscription::build_type($type);
  542. }
  543. return clone $subscription_types[$type];
  544. }
  545. /**
  546. * Build a subscriptions list collection with this name
  547. *
  548. * A new Notifications_Subscription_List will be created if not cached before,
  549. * and we'll invoke hook_notifications_subscription_list($name, $list) to collect subscriptions for this list.
  550. */
  551. function notifications_subscription_list($name) {
  552. $types = &drupal_static(__FUNCTION__);
  553. if (!isset($types[$name])) {
  554. $list = new Notifications_Subscription_List($name);
  555. // Modules can add or remove subscriptions from the list
  556. module_invoke_all('notifications_subscription_list', $name, $list);
  557. $types[$name] = $list;
  558. }
  559. return clone $types[$name];
  560. }
  561. /**
  562. * Implementation of hook_notifications_subscription_list().
  563. */
  564. function notifications_notifications_subscription_list($name, $list = NULL) {
  565. switch ($name) {
  566. case 'page subscriptions':
  567. // Get all subscriptions for the objects available in the current page for the current user
  568. $account = $GLOBALS['user'];
  569. if ($objects = module_invoke_all('notifications_subscription', 'page objects')) {
  570. if ($add = Notifications_Subscription::object_subscriptions($objects, $account)) {
  571. $list->add($add);
  572. }
  573. $list->set_user($account);
  574. }
  575. break;
  576. }
  577. }
  578. /**
  579. * Create notifications template object
  580. */
  581. function notifications_template($name) {
  582. $class = notifications_info('message templates', $name, 'class', 'Notifications_Message_Template');
  583. $info = notifications_info('message templates', $name);
  584. return new $class($info);
  585. }
  586. /**
  587. * Get info about templates
  588. *
  589. * @param $type
  590. * String, the subscriptions type OPTIONAL
  591. * @param $field
  592. * String, a specific field to retrieve info from OPTIONAL
  593. */
  594. function notifications_template_info($type = NULL, $field = NULL) {
  595. $types = notifications_info('notifications templates');
  596. return messaging_array_info($types, $type, $field);
  597. }
  598. /*** Old code ****/
  599. /**
  600. * Implementation of hook_permission()
  601. */
  602. function notifications_permission() {
  603. return array(
  604. 'administer notifications' => array(
  605. 'title' => t('Administer notifications'),
  606. 'description' => t('Administer all notifications options.'),
  607. ),
  608. 'create subscriptions' => array(
  609. 'title' => t('Create subscriptions'),
  610. 'description' => t('Create own subscriptions.'),
  611. ),
  612. 'maintain own subscriptions' => array(
  613. 'title' => t('Maintain own subscriptions'),
  614. 'description' => t('Create, delete or edit own subscriptions.'),
  615. ),
  616. 'manage all subscriptions' => array(
  617. 'title' => t('Administer subscriptions'),
  618. 'description' => t('Administer other subscriptions for other users.'),
  619. ),
  620. 'skip notifications' => array(
  621. 'title' => t('Skip notifications'),
  622. 'description' => t('Make changes with an option to skip notifications when available.'),
  623. ),
  624. );
  625. }
  626. /**
  627. * Implementation of hook_user().
  628. */
  629. function notifications_user_delete($user) {
  630. // Delete related data on tables
  631. Notifications_Subscription::delete_multiple(array('uid' => $user->uid));
  632. }
  633. /**
  634. * Implementation of hook_user().
  635. */
  636. function notifications_user($type, $edit, $user, $category = NULL) {
  637. switch ($type) {
  638. case 'update':
  639. if (isset($edit['status'])) {
  640. if ($edit['status'] == 0) { // user is being blocked now
  641. // Delete pending notifications and block existing active subscriptions
  642. db_query('UPDATE {notifications_subscription} SET status = %d WHERE status = %d AND uid = %d', Notifications_Subscription::STATUS_BLOCKED, Notifications_Subscription::STATUS_ACTIVE, $user->uid);
  643. notifications_queue()->queue_clean(array('uid' => $user->uid));
  644. }
  645. else {
  646. // User may be being unblocked, unblock subscriptions if any
  647. db_query('UPDATE {notifications_subscription} SET status = %d WHERE status = %d AND uid = %d', Notifications_Subscription::STATUS_ACTIVE, Notifications_Subscription::STATUS_BLOCKED, $user->uid);
  648. }
  649. }
  650. break;
  651. case 'after_update':
  652. // Update language for all existing subscriptions
  653. if ($language = user_preferred_language($user)) {
  654. db_query("UPDATE {notifications_subscription} SET language = '%s' WHERE uid = %d", $language->language, $user->uid);
  655. }
  656. break;
  657. }
  658. }
  659. /**
  660. * Gets a user setting, defaults to default system setting for each
  661. *
  662. * @param $name
  663. * Setting name
  664. * @param $account
  665. * Optional user account, will default to current user
  666. * @param $default
  667. * Optional default to return if this is not set
  668. */
  669. function notifications_user_setting($name, $account = NULL, $default = NULL) {
  670. global $user;
  671. $account = $account ? $account : $user;
  672. // Default send method is taken from messaging module
  673. if ($name == 'send_method') {
  674. return messaging_method_default($account);
  675. }
  676. $field = 'notifications_' . $name;
  677. if (isset($account->$field)) {
  678. return $account->$field;
  679. }
  680. else {
  681. return variable_get('notifications_default_' . $name, $default);
  682. }
  683. }
  684. /**
  685. * Create event object of given type
  686. *
  687. * Usage:
  688. * notifications_event('node', 'insert');
  689. *
  690. * @param $type
  691. * Event type key
  692. * @param $action
  693. * Event action
  694. */
  695. function notifications_event($type, $action = NULL) {
  696. $event = Notifications_Event::build_type($type, $action);
  697. $event->queue = variable_get('notifications_event_queue', 0);
  698. return $event;
  699. }
  700. /**
  701. * Check whether we have enabled events of this type
  702. *
  703. * @param $key
  704. * Event type key
  705. * @param $default
  706. * Default value to return if not set
  707. */
  708. function notifications_event_enabled($key, $default = TRUE) {
  709. $info = variable_get('notifications_event_enabled', array());
  710. $status = isset($info[$key]) ? $info[$key] : $default;
  711. // If this has a parent type, will be enabled just if parent is
  712. if ($status && ($parent = notifications_event_type($key, 'parent'))) {
  713. return notifications_event_enabled($parent, FALSE);
  714. }
  715. else {
  716. return $status;
  717. }
  718. }
  719. /**
  720. * Build subscription object properly
  721. *
  722. * @param $subscription
  723. * Subscription object, or array of properties or subscription type
  724. */
  725. function notifications_subscription_build($subscription) {
  726. return Notifications_Subscription::build_object($subscription);
  727. }
  728. /**
  729. * Update or create subscription
  730. *
  731. * This function checks for duplicated subscriptions before saving.
  732. * If a similar subscription is found it will be updated.
  733. * If no subscription is found and it is new, the sid will be added into the object.
  734. *
  735. * @param $subscription
  736. * Subscription object or array
  737. * @param $check
  738. * Whether to check parameters, can be skipped if they've been previously checked
  739. * @return integer
  740. * Failure to write a record will return FALSE. Otherwise SAVED_NEW or SAVED_UPDATED is returned depending on the operation performed.
  741. */
  742. function notifications_save_subscription(&$subscription, $check = TRUE) {
  743. // Build object if not built previously
  744. $subscription = notifications_subscription_build($subscription);
  745. // Check all the parameters are ok, add error message and return if not
  746. if ($check && !$subscription->check_all()) {
  747. return FALSE;
  748. }
  749. // Parameters are checked, now proceed
  750. if (!empty($subscription->sid)) {
  751. $op = 'update';
  752. $result = $subscription->save();
  753. }
  754. else {
  755. if ($duplicate = notifications_get_subscriptions(array('uid' => $subscription->uid, 'mdid' => $subscription->mdid, 'type' => $subscription->type, 'event_type' => $subscription->event_type, 'send_interval' => $subscription->send_interval, 'module' => $subscription->module), $subscription->get_fields(), TRUE)) {
  756. // We've found duplicates, resolve conflict updating first, deleting the rest
  757. // It is possible that we had a disabled one, this updating will fix it
  758. $update = array_shift($duplicate);
  759. unset($subscription->sid); // It may be 0
  760. foreach ($subscription as $key => $value) {
  761. if (isset($value)) {
  762. $update->$key = $value;
  763. }
  764. }
  765. $subscription->sid = $update->sid;
  766. // If there are more, delete, keep the table clean
  767. while ($dupe = array_shift($duplicate)) {
  768. Notifications_Subscription::delete_subscription($dupe->sid);
  769. }
  770. return notifications_save_subscription($subscription, $check);
  771. }
  772. else {
  773. $op = 'insert';
  774. $result = $subscription->save();
  775. }
  776. }
  777. // If the operation has worked so far, update fields and inform other modules
  778. if ($result !== FALSE) {
  779. $subscription->invoke_all($op);
  780. }
  781. return $result;
  782. }
  783. /**
  784. * Shorthand function for deleting everything related to a destination
  785. */
  786. function notifications_delete_destination($mdid) {
  787. Notifications_Subscription::delete_multiple(array('mdid' => $mdid));
  788. Messaging_Destination::delete_multiple(array('mdid' => $mdid));
  789. }
  790. /**
  791. * Load multiple subscriptions.
  792. */
  793. function notifications_get_subscriptions($conditions = array(), $fields = array(), $limit = FALSE) {
  794. // all fields in {notifications_subscription} are NOT NULL, so NULL is an undefined condition.
  795. // remove NULL from coditions, preseve 0 and FALSE.
  796. $conditions = array_filter($conditions, 'notifications_get_subscriptions_not_null');
  797. return Notifications_Subscription::load_multiple($conditions, $fields, $limit);
  798. }
  799. /**
  800. * Filter callback.
  801. */
  802. function notifications_get_subscriptions_not_null($value) {
  803. return !is_null($value);
  804. }
  805. /**
  806. * Create a wrapped object and keep a static cache of created objects.
  807. *
  808. * @param $type
  809. * Object type
  810. * @parma $value
  811. * Object or object key
  812. */
  813. function notifications_object($type, $value) {
  814. $cache = &drupal_static(__FUNCTION__);
  815. $class = notifications_object_type($type, 'class', 'Notifications_Drupal_Object');
  816. if (is_object($value) && is_a($value, $class)) {
  817. // Already an instance of the right class, just return
  818. return $object;
  819. }
  820. elseif (is_numeric($value) || is_string($value)) {
  821. $key = $value;
  822. }
  823. if (isset($key) && isset($cache[$type][$key])) {
  824. return $cache[$type][$key];
  825. }
  826. else {
  827. $object = Notifications_Object::build($type, $value);
  828. // Not all objects are cacheable, only if they have a value
  829. if ($key = $object->get_value()) {
  830. $cache[$type][$key] = $object;
  831. }
  832. return $object;
  833. }
  834. }
  835. /**
  836. * Get enabled subscription types
  837. */
  838. function notifications_subscription_enabled_types($type = NULL, $reset = FALSE) {
  839. $types = &drupal_static(__FUNCTION__, NULL, $reset);
  840. if (!isset($types)) {
  841. $types = array();
  842. foreach (notifications_subscription_type() as $key => $info) {
  843. if (empty($info['disabled']) && notifications_subscription_type_enabled($key)) {
  844. $types[$key] = notifications_subscription($key);
  845. }
  846. }
  847. }
  848. return $type ? $types[$type] : $types;
  849. }
  850. /**
  851. * Check if this type is enabled or get array with all enabled types
  852. */
  853. function notifications_subscription_type_enabled($type = NULL) {
  854. if ($type) {
  855. $info = notifications_subscription_type($type);
  856. return empty($info['disabled']) && (!isset($info['enabled']) || $info['enabled']);
  857. }
  858. else {
  859. $types = array_keys(notifications_subscription_type());
  860. return array_filter($types, 'notifications_subscription_type_enabled'); //array_combine($types, $types)
  861. }
  862. }
  863. /**
  864. * Get information about subscriptions fields
  865. *
  866. * Replaces notifications_field_type()
  867. */
  868. function notifications_field_type($type = NULL, $property = NULL, $default = NULL) {
  869. $fields = notifications_info('field types');
  870. return messaging_array_info($fields, $type, $property, $default);
  871. }
  872. /**
  873. * Filter elements in an array of arrays/objects that match some condition
  874. *
  875. * @param $array
  876. * Data array to be filtered.
  877. * @param $filter
  878. * Array of field => value pairs
  879. * @param $reverse
  880. * Reverse filter, return elements that don't match
  881. */
  882. function notifications_array_filter($array, $filter, $reverse = FALSE) {
  883. if (!$filter) {
  884. return $array;
  885. }
  886. foreach ($array as $key => $data) {
  887. $compare = is_object($data) ? (array)$data : $data;
  888. $match = count(array_intersect_assoc($filter, $compare)) == count($filter);
  889. if ($match && $reverse || !$match && !$reverse) {
  890. unset($array[$key]);
  891. }
  892. }
  893. return $array;
  894. }
  895. /**
  896. * Array item callback to format title and description
  897. */
  898. function notifications_format_title_description($item) {
  899. if (is_object($item)) {
  900. $title = check_plain($item->get_title());
  901. $description = check_plain($item->get_description());
  902. }
  903. elseif (is_array($item)) {
  904. $title = isset($item['title']) ? check_plain($item['title']) : t('no title');
  905. $description = isset($item['description']) ? check_plain($item['description']) : '';
  906. }
  907. return '<strong>' . $title . '</strong> ' . $description;
  908. }
  909. /**
  910. * Serialize an array ordering the keys before.
  911. *
  912. * This is useful for cache indexes and signatures.
  913. */
  914. function notifications_array_serialize($array) {
  915. if (!$array) {
  916. return '';
  917. }
  918. // First we sort and serialize multiple conditions
  919. foreach ($array as $key => $value) {
  920. if (is_array($value)) {
  921. asort($value);
  922. $array[$key] = implode(':', $value);
  923. }
  924. }
  925. // Now we sort the whole condtions array maintaining index association
  926. ksort($array);
  927. return implode(',', array_keys($array)) . '/' . implode(',', $array);
  928. }
  929. /**
  930. * Implementation of hook_messaging()
  931. *
  932. * This hook provides information about the mensaje templates this module uses and related tokens.
  933. *
  934. * Depending on $op, this hook takes different parameters and returns different pieces of information:
  935. *
  936. * - 'message groups'
  937. * Get array of message groups, each of which will have one or more keys for different templates
  938. * Each group should have a unique key, so it should start with the module name
  939. * - 'message keys'
  940. * Get message template parts for a given group ($arg1)
  941. * Return array of key => name for each part
  942. * - 'messages'
  943. * Get default message templates for a given group ($arg1).
  944. * It should return default texts, indexed by message key that will be the default templates
  945. * These templates may be edited on the 'Messaging templates' page
  946. * - 'tokens'
  947. * Get available tokens for a given message group and key ($arg1).
  948. * Return array of token keys that will be available for this message templates
  949. * The tokens themselves may be default tokens (provided by token module) or we can add new
  950. * tokens implementing hook_token_list() and hook_token_value()
  951. *
  952. * @param $op
  953. * Operation, type of information to retrieve
  954. * @param $arg1, $arg2...
  955. * Different parameters depending on $op
  956. */
  957. function notifications_messaging($op, $arg1 = NULL, $arg2 = NULL) {
  958. switch ($op) {
  959. case 'message types':
  960. $info['notifications'] = array(
  961. 'name' => t('Notifications'),
  962. 'description' => t('Messages coming from user subscriptions and system events')
  963. );
  964. return $info;
  965. }
  966. }
  967. /**
  968. * Implements hook_messaging_method()
  969. */
  970. function notifications_messaging_method($op, $method, $param = NULL) {
  971. switch ($op) {
  972. case 'replace':
  973. // Replace old method $method by new method $param
  974. db_update('notifications_subscription')
  975. ->fields(array('send_method' => $param))
  976. ->condition('send_method', $method)
  977. ->execute();
  978. break;
  979. case 'disable':
  980. // Disable all subscriptions for disabled method
  981. db_update('notifications_subscription')
  982. ->fields(array('status' => Notifications_Subscription::STATUS_NOSEND))
  983. ->condition('send_method', $method)
  984. ->execute();
  985. break;
  986. }
  987. }
  988. /**
  989. * Get event types. Invoking this function will also load the event API
  990. *
  991. * Was: notifications_event_type_enabled
  992. */
  993. function notifications_event_enabled_types($typekey = NULL, $property = NULL, $default = NULL) {
  994. $enabled = &drupal_static(__FUNCTION__);
  995. if (!isset($enabled)) {
  996. $enabled = array();
  997. foreach (notifications_event_type() as $type => $event_type) {
  998. if (empty($event['disabled']) && notifications_event_enabled($type)) {
  999. $enabled[$type] = $event_type;
  1000. }
  1001. }
  1002. }
  1003. return messaging_array_info($info, $typekey, $property, $default);
  1004. }
  1005. /**
  1006. * Information about digesting method for a send interval.
  1007. *
  1008. * @return array()
  1009. * Ditest information for that interval, or all the information if no interval
  1010. */
  1011. function notifications_build_method($send_interval = NULL, $refresh = FALSE) {
  1012. $build_methods = notifications_info('build methods', NULL, $refresh);
  1013. $intervals = variable_get('notifications_digest_methods', array());
  1014. if (is_null($send_interval)) {
  1015. return $build_methods;
  1016. }
  1017. elseif (!empty($intervals[$send_interval]) && isset($build_methods[$intervals[$send_interval]])) {
  1018. return $build_methods[$intervals[$send_interval]];
  1019. }
  1020. else {
  1021. // Default, that will be always the simple one
  1022. return $build_methods['simple'];
  1023. }
  1024. }
  1025. /**
  1026. * Invoke hook_notifications($name) on all modules and get a property from the array
  1027. *
  1028. * Properties will be overridden by the value of 'notifications_option_[$name]
  1029. */
  1030. function notifications_info($name, $type = NULL, $property = NULL, $default = NULL) {
  1031. $_name = strtr($name, ' ', '_');
  1032. $info = &drupal_static('notifications_info_' . $_name);
  1033. if (!isset($info)) {
  1034. $info = module_invoke_all('notifications', $name);
  1035. // Override with variable values
  1036. foreach ($info as $key => &$data) {
  1037. if ($options = notifications_option_get($_name . '_' . $key)) {
  1038. $data = array_merge($data, $options);
  1039. }
  1040. }
  1041. // Provide alter hook: notifications_name
  1042. drupal_alter('notifications_' . $_name, $info);
  1043. }
  1044. return messaging_array_info($info, $type, $property, $default);
  1045. }
  1046. /**
  1047. * Get value from notifications_option_* variables
  1048. *
  1049. * These variables may be overridden for a page request without affecting the stored variables
  1050. *
  1051. * @param $name
  1052. * Variable name, will be prefixed with 'notifications_option_'
  1053. * @param $index
  1054. * Optional index if it s an array variable
  1055. */
  1056. function notifications_option_get($name, $index = NULL, $default = NULL) {
  1057. $options = &drupal_static('notifications_options', array());
  1058. if (!array_key_exists($name, $options)) {
  1059. $options[$name] = variable_get('notifications_option_' . $name, NULL);
  1060. }
  1061. if (isset($index)) {
  1062. return isset($options[$name][$index]) ? $options[$name][$index] : $default;
  1063. }
  1064. else {
  1065. return $options[$name];
  1066. }
  1067. }
  1068. /**
  1069. * Set value from notifications_option_* variables
  1070. *
  1071. * @param $name
  1072. * Variable name, will be prefixed with 'notifications_option_'
  1073. * @param $value
  1074. * New variable value
  1075. * @param $index
  1076. * Optional index if it s an array variable
  1077. * @param $request
  1078. * Set only for this page request (do not save to variables table)
  1079. */
  1080. function notifications_option_set($name, $value, $index = NULL, $request = FALSE) {
  1081. // Make sure the variable is loaded into the static variable
  1082. notifications_option_get($name);
  1083. $options = &drupal_static('notifications_options', array());
  1084. if (isset($index)) {
  1085. $options[$name][$index] = $value;
  1086. }
  1087. else {
  1088. $options[$name] = $value;
  1089. }
  1090. if (!$request) {
  1091. variable_set('notifications_option_' . $name, $options[$name]);
  1092. }
  1093. }
  1094. /**
  1095. * Get an array of options indexed by type
  1096. *
  1097. * Example: If we want to get the 'enabled' property for all subscription types
  1098. * - $name = 'subscription_types'
  1099. * - $types = array('type1', 'type2'...)
  1100. * We will iterate over all the 'notifications_option_subscription_type_$type' array variables
  1101. * and get the $property we want for them
  1102. */
  1103. function notifications_option_array_get($name, $type_list, $property, $default = NULL) {
  1104. $type_values = array();
  1105. foreach ($type_list as $type) {
  1106. // Example 'notifications_option_subscription_types_thread' => array()
  1107. $value = notifications_option_get($name . '_' . $type, array());
  1108. if (isset($value[$property])) {
  1109. $type_values[$type] = $value[$property];
  1110. }
  1111. elseif (isset($default)) {
  1112. $type_values[$type] = $default;
  1113. }
  1114. }
  1115. return $type_values;
  1116. }
  1117. /**
  1118. * Set the same property for a family of array variables
  1119. */
  1120. function notifications_option_array_set($name, $property, $values) {
  1121. $options = &drupal_static('notifications_options');
  1122. foreach ($values as $type => $value) {
  1123. $array = notifications_option_get($name . '_' . $type);
  1124. $array[$property] = $value;
  1125. notifications_option_set($name . '_' . $type, $array);
  1126. }
  1127. }
  1128. /**
  1129. * List of send intervals, only Immediately if no advanced queue enabled
  1130. */
  1131. function notifications_send_intervals($account = NULL) {
  1132. if (function_exists('notifications_queue_send_intervals')) {
  1133. return notifications_queue_send_intervals($account);
  1134. }
  1135. else {
  1136. return array(0 => t('Immediately'));
  1137. }
  1138. }
  1139. /**
  1140. * Get list of send methods for user or anonymous account
  1141. */
  1142. function notifications_send_methods($account) {
  1143. // We restrict send methods for anonymous accounts when edited by regular users
  1144. if (empty($account->uid) && function_exists('notifications_anonymous_send_methods')) {
  1145. return notifications_anonymous_send_methods();
  1146. }
  1147. else {
  1148. return _notifications_send_methods($account);
  1149. }
  1150. }
  1151. /**
  1152. * List of send methods
  1153. *
  1154. * @param $account
  1155. * Optional user account, for checking permissions against this account
  1156. */
  1157. function _notifications_send_methods($account = NULL) {
  1158. return variable_get('notifications_send_methods', messaging_method_list($account));
  1159. }
  1160. /**
  1161. * Implementation of hook_theme()
  1162. */
  1163. function notifications_theme() {
  1164. return array(
  1165. 'notifications_table_form' => array(
  1166. 'render element' => 'form',
  1167. 'file' => 'notifications.pages.inc',
  1168. ),
  1169. 'notifications_subscription_fields' => array(
  1170. 'render element' => 'element',
  1171. 'file' => 'notifications.pages.inc',
  1172. ),
  1173. 'notifications_admin_table_form' => array(
  1174. 'render element' => 'form',
  1175. 'file' => 'notifications.admin.inc',
  1176. ),
  1177. 'notifications_admin_subscription_list' => array(
  1178. 'variables' => array('sids' => NULL, 'limit' => 10),
  1179. 'file' => 'notifications.admin.inc',
  1180. )
  1181. );
  1182. }
  1183. /**
  1184. * Implementation of hook_forms()
  1185. */
  1186. function notifications_forms($form_id, $args) {
  1187. if (strpos($form_id, 'notifications_subscription') === 0) {
  1188. foreach (array('view', 'edit', 'delete', 'add', 'subscribe', 'unsubscribe') as $op) {
  1189. $forms['notifications_subscription_' . $op . '_form'] = array(
  1190. 'callback' => 'notifications_subscription_form',
  1191. 'callback arguments' => array($op),
  1192. );
  1193. }
  1194. return $forms;
  1195. }
  1196. }
  1197. /**
  1198. * Subscription form ('add', 'edit', 'confirm')
  1199. */
  1200. function notifications_subscription_form($form, &$form_state, $operation, $subscription) {
  1201. return $subscription->get_form($operation, $form, $form_state);
  1202. }
  1203. /**
  1204. * Validate form submission
  1205. */
  1206. function notifications_subscription_form_validate($form, &$form_state) {
  1207. return Notifications_Subscription::build_from_submission($form, $form_state)
  1208. ->form_validate($form, $form_state);
  1209. }
  1210. /**
  1211. * Process form submission
  1212. */
  1213. function notifications_subscription_form_submit($form, &$form_state) {
  1214. return Notifications_Subscription::build_from_submission($form, $form_state)
  1215. ->form_submit($form, $form_state);
  1216. }
  1217. /**
  1218. * Form with subscription list
  1219. */
  1220. function notifications_subscription_list_form($form, &$form_state, $type, $subscriptions) {
  1221. $form = Notifications_Subscription_List::build_list($subscriptions)
  1222. ->get_form($type, $form, $form_state);
  1223. $form['#submit'][] = 'notifications_subscription_list_form_validate';
  1224. $form['#validate'][] = 'notifications_subscription_list_form_submit';
  1225. return $form;
  1226. }
  1227. /**
  1228. * Validate list form submission
  1229. */
  1230. function notifications_subscription_list_form_validate($form, &$form_state) {
  1231. return Notifications_Subscription_List::build_from_submission($form, $form_state)
  1232. ->form_validate($form, $form_state);
  1233. }
  1234. /**
  1235. * Process list form submission
  1236. */
  1237. function notifications_subscription_list_form_submit($form, &$form_state) {
  1238. return Notifications_Subscription_List::build_from_submission($form, $form_state)
  1239. ->form_submit($form, $form_state);
  1240. }
  1241. /**
  1242. * Implements hook_token_info().
  1243. */
  1244. function notifications_token_info() {
  1245. $info['tokens']['user']['unsubscribe-url'] = array(
  1246. 'name' => t("Unsubscribe URL"),
  1247. 'description' => t("Signed URL for cancelling all user subscriptions."),
  1248. );
  1249. return $info;
  1250. }
  1251. /**
  1252. * Implements hook_tokens().
  1253. */
  1254. function notifications_tokens($type, $tokens, array $data = array(), array $options = array()) {
  1255. if ($type == 'user' && !empty($data['user'])) {
  1256. $user = $data['user'];
  1257. $replacements = array();
  1258. foreach ($tokens as $name => $original) {
  1259. switch ($name) {
  1260. // Signed unsubscribe url
  1261. case 'unsubscribe-url':
  1262. $url_options = array('absolute' => TRUE);
  1263. if ($user->uid) {
  1264. $url_options['signed'] = TRUE;
  1265. $path = 'notifications/unsubscribe/user/' . $user->uid;
  1266. $url_options = notifications_url_options($path, $url_options);
  1267. }
  1268. else {
  1269. $path = 'notifications/unsubscribe';
  1270. }
  1271. $replacements[$original] = url($path, $url_options);
  1272. break;
  1273. }
  1274. }
  1275. return $replacements;
  1276. }
  1277. }
  1278. /**
  1279. * Fill some url options
  1280. */
  1281. /**
  1282. * Wrapper for url() function with some more options
  1283. */
  1284. function notifications_url_options($path, $options = array()) {
  1285. $options += array(
  1286. 'skip_confirmation' => FALSE,
  1287. 'query' => array(),
  1288. );
  1289. // If skip confirmation, links need to be signed
  1290. $options += array('signed' => $options['skip_confirmation']);
  1291. // If signed, add timestamp and signature, and maybe skip confirmation
  1292. if ($options['signed']) {
  1293. $options['query'] += array('timestamp' => REQUEST_TIME);
  1294. if ($options['skip_confirmation']) {
  1295. $options['query']['skip'] = 1;
  1296. }
  1297. $options['query']['signature'] = notifications_url_signature($path, $options['query']);
  1298. }
  1299. return $options;
  1300. }
  1301. /**
  1302. * Signature for url parameters
  1303. *
  1304. * @param $path
  1305. * Path or array with path elements
  1306. * @param $query
  1307. * Query string elements
  1308. */
  1309. function notifications_url_signature($path, $query = array()) {
  1310. $path = is_array($path) ? implode('/', $path) : $path;
  1311. if (isset($query['signature'])) {
  1312. unset($query['signature']);
  1313. }
  1314. $string = $query ? notifications_array_serialize($query) : 'none';
  1315. return md5('notifications' . drupal_get_private_key() . ':' . $path . ':' . $string);
  1316. }
  1317. /**
  1318. * Implementation of hook_cron()
  1319. *
  1320. * Keep logs clean
  1321. */
  1322. function notifications_cron() {
  1323. if ($log_time = variable_get('notifications_event_log', NOTIFICATIONS_EVENT_LOG)) {
  1324. db_delete('notifications_event')
  1325. ->condition('log', 1)
  1326. ->condition('created', REQUEST_TIME - $log_time, '<')
  1327. ->execute();
  1328. }
  1329. }
  1330. /**
  1331. * Implementation of hook_cron_queue_info()
  1332. */
  1333. function notifications_cron_queue_info() {
  1334. return array(
  1335. 'notifications_event' => array(
  1336. 'worker callback' => 'notifications_cron_queue_event_worker',
  1337. 'time' => 60,
  1338. ));
  1339. }
  1340. /**
  1341. * Worker callback. Check whether the message has expired before sending out.
  1342. */
  1343. function notifications_cron_queue_event_worker($event) {
  1344. $event->send_all();
  1345. $event->done();
  1346. }