useremailsummaryhandler.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. /**
  3. * StatusNet - the distributed open-source microblogging tool
  4. *
  5. * Handler for queue items of type 'usersum', sends an email summaries
  6. * to a particular user.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. * @category Sample
  22. * @package StatusNet
  23. * @author Evan Prodromou <evan@status.net>
  24. * @copyright 2010 StatusNet, Inc.
  25. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  26. * @link http://status.net/
  27. */
  28. if (!defined('STATUSNET')) {
  29. exit(1);
  30. }
  31. /**
  32. * Handler for queue items of type 'usersum', sends an email summaries
  33. * to a particular user.
  34. *
  35. * @category Email
  36. * @package StatusNet
  37. * @author Evan Prodromou <evan@status.net>
  38. * @copyright 2010 StatusNet, Inc.
  39. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  40. * @link http://status.net/
  41. */
  42. class UserEmailSummaryHandler extends QueueHandler
  43. {
  44. // Maximum number of notices to include by default. This is probably too much.
  45. const MAX_NOTICES = 200;
  46. /**
  47. * Return transport keyword which identifies items this queue handler
  48. * services; must be defined for all subclasses.
  49. *
  50. * Must be 8 characters or less to fit in the queue_item database.
  51. * ex "email", "jabber", "sms", "irc", ...
  52. *
  53. * @return string
  54. */
  55. function transport()
  56. {
  57. return 'usersum';
  58. }
  59. /**
  60. * Send a summary email to the user
  61. *
  62. * @param mixed $object
  63. * @return boolean true on success, false on failure
  64. */
  65. function handle($user_id)
  66. {
  67. // Skip if they've asked not to get summaries
  68. $ess = Email_summary_status::getKV('user_id', $user_id);
  69. if (!empty($ess) && !$ess->send_summary) {
  70. common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
  71. return true;
  72. }
  73. $since_id = null;
  74. if (!empty($ess)) {
  75. $since_id = $ess->last_summary_id;
  76. }
  77. $user = User::getKV('id', $user_id);
  78. if (empty($user)) {
  79. common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
  80. return true;
  81. }
  82. if (empty($user->email)) {
  83. common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
  84. return true;
  85. }
  86. $profile = $user->getProfile();
  87. if (empty($profile)) {
  88. common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
  89. return true;
  90. }
  91. // An InboxNoticeStream for a certain user, scoped to its own view
  92. $stream = new InboxNoticeStream($profile);
  93. $notice = $stream->getNotices(0, self::MAX_NOTICES, $since_id);
  94. if (empty($notice) || $notice->N == 0) {
  95. common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
  96. return true;
  97. }
  98. // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
  99. // figuring out a better way. -ESP
  100. $new_top = null;
  101. if ($notice->fetch()) {
  102. $new_top = $notice->id;
  103. }
  104. // TRANS: Subject for e-mail.
  105. $subject = sprintf(_m('Your latest updates from %s'), common_config('site', 'name'));
  106. $out = new XMLStringer(true);
  107. $out->elementStart('html');
  108. $out->elementStart('head');
  109. $out->element('title', null, $subject);
  110. $out->elementEnd('head');
  111. $out->elementStart('body');
  112. $out->elementStart('div', array('width' => '100%',
  113. 'style' => 'background-color: #ffffff; border: 4px solid #4c609a; padding: 10px;'));
  114. $out->elementStart('div', array('style' => 'color: #ffffff; background-color: #4c609a; font-weight: bold; margin-bottom: 10px; padding: 4px;'));
  115. // TRANS: Text in e-mail summary.
  116. // TRANS: %1$s is the StatusNet sitename, %2$s is the recipient's profile name.
  117. $out->raw(sprintf(_m('Recent updates from %1$s for %2$s:'),
  118. common_config('site', 'name'),
  119. $profile->getBestName()));
  120. $out->elementEnd('div');
  121. $out->elementStart('table', array('width' => '550px',
  122. 'style' => 'border: none; border-collapse: collapse;', 'cellpadding' => '6'));
  123. do {
  124. $profile = Profile::getKV('id', $notice->profile_id);
  125. if (empty($profile)) {
  126. continue;
  127. }
  128. $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE);
  129. $out->elementStart('tr');
  130. $out->elementStart('td', array('width' => AVATAR_STREAM_SIZE,
  131. 'height' => AVATAR_STREAM_SIZE,
  132. 'align' => 'left',
  133. 'valign' => 'top',
  134. 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
  135. $out->element('img', array('src' => $avatarUrl,
  136. 'width' => AVATAR_STREAM_SIZE,
  137. 'height' => AVATAR_STREAM_SIZE,
  138. 'alt' => $profile->getBestName()));
  139. $out->elementEnd('td');
  140. $out->elementStart('td', array('align' => 'left',
  141. 'valign' => 'top',
  142. 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
  143. $out->element('a', array('href' => $profile->profileurl),
  144. $profile->nickname);
  145. $out->text(' ');
  146. $out->raw($notice->getRendered());
  147. $out->elementStart('div', array('style' => 'font-size: 0.8em; padding-top: 4px;'));
  148. $noticeurl = $notice->getLocalUrl();
  149. // above should always return an URL
  150. assert(!empty($noticeurl));
  151. $out->elementStart('a', array('rel' => 'bookmark',
  152. 'href' => $noticeurl));
  153. $dt = common_date_iso8601($notice->created);
  154. $out->element('abbr', array('style' => 'border-bottom: none;',
  155. 'title' => $dt),
  156. common_date_string($notice->created));
  157. $out->elementEnd('a');
  158. $out->element('a', array('href' => $notice->getConversationUrl()),
  159. // TRANS: Link text for link to conversation view.
  160. _m('in context'));
  161. $out->elementEnd('div');
  162. $out->elementEnd('td');
  163. $out->elementEnd('tr');
  164. } while ($notice->fetch());
  165. $out->elementEnd('table');
  166. // TRANS: Link text for link to e-mail settings.
  167. // TRANS: %1$s is a link to the e-mail settings, %2$s is the StatusNet sitename.
  168. $out->raw("<p>" . sprintf(_m('<a href="%1$s">change your email settings for %2$s</a>'),
  169. common_local_url('emailsettings'),
  170. common_config('site', 'name'))."</p>");
  171. $out->elementEnd('div');
  172. $out->elementEnd('body');
  173. $out->elementEnd('html');
  174. $body = $out->getString();
  175. // FIXME: do something for people who don't like HTML email
  176. mail_to_user($user,
  177. $subject,
  178. $body,
  179. array('Content-Type' => 'text/html; charset=utf-8',
  180. 'Mime-Version' => '1.0'));
  181. if (empty($ess)) {
  182. $ess = new Email_summary_status();
  183. $ess->user_id = $user_id;
  184. $ess->created = common_sql_now();
  185. $ess->last_summary_id = $new_top;
  186. $ess->modified = common_sql_now();
  187. $ess->insert();
  188. } else {
  189. $orig = clone($ess);
  190. $ess->last_summary_id = $new_top;
  191. $ess->modified = common_sql_now();
  192. $ess->update($orig);
  193. }
  194. return true;
  195. }
  196. }