]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/EmailSummary/useremailsummaryhandler.php
stylesheet for outgoing email
[quix0rs-gnu-social.git] / plugins / EmailSummary / useremailsummaryhandler.php
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
29 if (!defined('STATUSNET')) {
30     exit(1);
31 }
32
33 /**
34  * Handler for queue items of type 'usersum', sends an email summaries
35  * to a particular user.
36  *
37  * @category  Email
38  * @package   StatusNet
39  * @author    Evan Prodromou <evan@status.net>
40  * @copyright 2010 StatusNet, Inc.
41  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
42  * @link      http://status.net/
43  */
44
45 class UserEmailSummaryHandler extends QueueHandler
46 {
47     // Maximum number of notices to include by default. This is probably too much.
48     
49     const MAX_NOTICES = 200;
50     
51     /**
52      * Return transport keyword which identifies items this queue handler
53      * services; must be defined for all subclasses.
54      *
55      * Must be 8 characters or less to fit in the queue_item database.
56      * ex "email", "jabber", "sms", "irc", ...
57      *
58      * @return string
59      */
60     
61     function transport()
62     {
63         return 'sitesum';
64     }
65
66     /**
67      * Send a summary email to the user
68      * 
69      * @param mixed $object
70      * @return boolean true on success, false on failure
71      */
72     
73     function handle($user_id)
74     {
75         // Skip if they've asked not to get summaries
76
77         $ess = Email_summary_status::staticGet('user_id', $user_id);
78         
79         if (!empty($ess) && !$ess->send_summary) {
80             common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
81             return true;
82         }
83
84         $since_id = null;
85         
86         if (!empty($ess)) {
87             $since_id = $ess->last_summary_id;
88         }
89           
90         $user = User::staticGet('id', $user_id);
91
92         if (empty($user)) {
93             common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
94             return true;
95         }
96         
97         if (empty($user->email)) {
98             common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
99             return true;
100         }
101         
102         $profile = $user->getProfile();
103         
104         if (empty($profile)) {
105             common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
106             return true;
107         }
108         
109         $notice = $user->ownFriendsTimeline(0, self::MAX_NOTICES, $since_id);
110
111         if (empty($notice) || $notice->N == 0) {
112             common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
113             return true;
114         }
115
116         // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
117         // figuring out a better way. -ESP
118
119         $new_top = null;
120         
121         if ($notice instanceof ArrayWrapper) {
122             $new_top = $notice->_items[0]->id;
123         }
124         
125         $out = new XMLStringer();
126
127         $out->raw('<style>'.$this->stylesheet().'</style>');
128         
129         $out->raw(sprintf(_('<p>Recent updates from %1s for %2s:</p>'),
130                           common_config('site', 'name'),
131                           $profile->getBestName()));
132         
133         $nl = new NoticeList($notice, $out);
134
135         // Outputs to the string
136         
137         $nl->show();
138         
139         $out->raw(sprintf(_('<p><a href="%1s">change your email settings for %2s</a></p>'),
140                           common_local_url('emailsettings'),
141                           common_config('site', 'name')));
142
143         $body = $out->getString();
144         
145         // FIXME: do something for people who don't like HTML email
146         
147         mail_to_user($user, _('Updates from your network'), $body,
148                      array('Content-Type' => 'text/html; charset=UTF-8'));
149
150         if (empty($ess)) {
151             
152             $ess = new Email_summary_status();
153             
154             $ess->user_id         = $user_id;
155             $ess->created         = common_sql_now();
156             $ess->last_summary_id = $new_top;
157             $ess->modified        = common_sql_now();
158
159             $ess->insert();
160             
161         } else {
162             
163             $orig = clone($ess);
164             
165             $ess->last_summary_id = $new_top;
166             $ess->modified        = common_sql_now();
167
168             $ess->update();
169         }
170         
171         return true;
172     }
173     
174     function stylesheet()
175     {
176         $ss = <<<END_OF_STYLESHEET
177
178 #notices_primary {
179     padding-top: 8px;
180     clear: both;
181 }
182
183 #notices_primary h2 {
184     display: none;
185 }
186
187 .notice {
188     list-style-type: none;
189     margin-bottom: 25px;
190     clear: left;
191     min-height: 54px;
192     padding-bottom: 2px;
193 }
194
195 .notice, .profile, .application {
196     position:relative;
197     clear:both;
198     float:left;
199     width:100%;
200 }
201
202 .notice .author {
203     margin-right: 8px;
204 }
205
206 .fn {
207     overflow: hidden;
208 }
209
210 .notice .author .fn {
211     font-weight: bold;
212 }
213
214 #core .vcard .photo {
215     display: inline;
216     margin-right: 11px;
217     float: left;
218 }
219
220 #content .notice .author .photo {
221     position: absolute;
222     top: 4px;
223     left: 4px;
224     float: none;
225 }
226
227 #content .notice .entry-title {
228     margin: 2px 7px 0px 59px;
229 }
230
231 .vcard .url {
232     text-decoration:none;
233 }
234 .vcard .url:hover {
235     text-decoration:underline;
236 }
237
238 .notice .entry-title {
239     overflow:hidden;
240     word-wrap:break-word;
241 }
242
243 .notice .entry-title.ov {
244 overflow:visible;
245 }
246
247 #showstream h1 { 
248     display:none;
249 }
250
251 #showstream .notice .entry-title, #showstream .notice div.entry-content {
252     margin-left: 0;
253 }
254
255 #showstream #content .notice .author {
256     display: none;
257 }
258
259 #showstream .notice {
260     min-height: 1em; 
261 }
262
263 #shownotice .vcard .photo {
264     margin-bottom: 4px;
265 }
266
267 #shownotice .notice .entry-title {
268     margin-left:110px;
269     font-size:2.2em;
270     min-height:123px;
271     font-size: 1.6em;
272     line-height: 1.2em;
273 }
274
275 #shownotice .notice div.entry-content {
276     margin-left:0;
277 }
278
279 .notice p.entry-content {
280     display:inline;
281 }
282
283 .notice div.entry-content {
284     clear:left;
285     float:left;
286     margin-left:59px;
287     margin-top: 10px;
288 }
289
290 .entry-content .repeat {
291     display: block;
292 }
293
294 .entry-content .repeat .photo {
295 float:none;
296 margin-right:1px;
297 position:relative;
298 top:4px;
299 left:0;
300 }
301
302 .notice-options {
303     float: right;    
304     margin-top: 12px;
305     margin-right: -6px;
306 }
307
308 .notice-options fieldset {
309     border: none;
310 }
311
312 .notice-options legend {
313     display: none;
314 }
315
316 .notice-options form, .notice-options a, .notice-options .repeated {
317     float: left;
318     margin-right: 10px;
319 }
320
321 .notice-options input, .notice-options a, .notice-options .repeated {    
322     text-indent: -9999px;
323     outline:none;
324 }
325
326 .notice-options input.submit, .notice-options a, .notice-options .repeated {
327     display: block;
328     border: 0;
329     height: 16px;
330     width: 16px;
331 }
332
333 .notice-options input.submit, .notice-options a {
334     opacity: 0.6;
335 }
336
337 .notice-options input.submit:hover, .notice-options a:hover {
338     opacity: 1;
339 }
340
341 .notice .attachment {
342     position:relative;
343     padding-left:16px;
344 }
345
346 .notice .attachment.more {
347 text-indent:-9999px;
348 width:16px;
349 height:16px;
350 display:inline-block;
351 overflow:hidden;
352 vertical-align:middle;
353 margin-left:4px;
354 }
355
356 #attachments .attachment,
357 .notice .attachment.more {
358 padding-left:0;
359 }
360
361 .notice .attachment img {
362 position:absolute;
363 top:18px;
364 left:0;
365 z-index:99;
366 }
367
368 #shownotice .notice .attachment img {
369 position:static;
370 }
371
372 #attachments {
373 clear:both;
374 float:left;
375 width:100%;
376 margin-top:18px;
377 }
378 #attachments dt {
379 font-weight:bold;
380 font-size:1.3em;
381 margin-bottom:4px;
382 }
383
384 #attachments ol li {
385 margin-bottom:18px;
386 list-style-type:decimal;
387 float:left;
388 clear:both;
389 }
390
391 #jOverlayContent,
392 #jOverlayContent #content,
393 #jOverlayContent #content_inner {
394 width: auto !important;
395 margin-bottom:0;
396 }
397 #jOverlayContent #content {
398 padding:11px;
399 min-height:auto;
400     border: 1px solid #fff;
401 }
402 #jOverlayContent .entry-title {
403 display:block;
404 margin-bottom:11px;
405 }
406 #jOverlayContent button {
407     position:absolute;
408     top: 5px;
409     right: 20px;
410 }
411 #jOverlayContent h1 {
412 max-width:425px;
413 }
414 #jOverlayLoading {
415 top:5%;
416 left:40%;
417 }
418 #attachment_view img {
419 max-width:480px;
420 max-height:480px;
421 }
422 #attachment_view #oembed_info {
423 margin-top:11px;
424 }
425 #attachment_view #oembed_info dt,
426 #attachment_view #oembed_info dd {
427 float:left;
428 }
429 #attachment_view #oembed_info dt {
430 clear:left;
431 margin-right:11px;
432 font-weight:bold;
433 }
434 #attachment_view #oembed_info dt:after {
435 content: ":";
436 }
437
438 #content .notice .notice {
439     width: 98%;
440     margin-left: 2%;
441     margin-top: 16px;
442     margin-bottom: 10px;
443 }
444
445 .notice .notice {
446 background-color:rgba(200, 200, 200, 0.050);
447 }
448 .notice .notice .notice {
449 background-color:rgba(200, 200, 200, 0.100);
450 }
451 .notice .notice .notice .notice {
452 background-color:rgba(200, 200, 200, 0.150);
453 }
454 .notice .notice .notice .notice .notice {
455 background-color:rgba(200, 200, 200, 0.300);
456 }
457
458 END_OF_STYLESHEET;
459
460         return $ss;
461     }
462     
463 }
464