]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - lib/useractivitystream.php
Don't abort if an activity throws an exception when backing up
[quix0rs-gnu-social.git] / lib / useractivitystream.php
1 <?php
2 /*
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010 StatusNet, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * Class for activity streams
22  *
23  * Includes faves, notices, and subscriptions.
24  *
25  * We extend atomusernoticefeed since it does some nice setup for us.
26  *
27  */
28 class UserActivityStream extends AtomUserNoticeFeed
29 {
30     public $activities = array();
31
32     const OUTPUT_STRING = 1;
33     const OUTPUT_RAW = 2;
34     public $outputMode = self::OUTPUT_STRING;
35
36     /**
37      *
38      * @param User $user
39      * @param boolean $indent
40      * @param boolean $outputMode: UserActivityStream::OUTPUT_STRING to return a string,
41      *                           or UserActivityStream::OUTPUT_RAW to go to raw output.
42      *                           Raw output mode will attempt to stream, keeping less
43      *                           data in memory but will leave $this->activities incomplete.
44      */
45     function __construct($user, $indent = true, $outputMode = UserActivityStream::OUTPUT_STRING)
46     {
47         parent::__construct($user, null, $indent);
48
49         $this->outputMode = $outputMode;
50         if ($this->outputMode == self::OUTPUT_STRING) {
51             // String buffering? Grab all the notices now.
52             $notices = $this->getNotices();
53         } elseif ($this->outputMode == self::OUTPUT_RAW) {
54             // Raw output... need to restructure from the stringer init.
55             $this->xw = new XMLWriter();
56             $this->xw->openURI('php://output');
57             if(is_null($indent)) {
58                 $indent = common_config('site', 'indent');
59             }
60             $this->xw->setIndent($indent);
61
62             // We'll fetch notices later.
63             $notices = array();
64         } else {
65             throw new Exception('Invalid outputMode provided to ' . __METHOD__);
66         }
67
68         // Assume that everything but notices is feasible
69         // to pull at once and work with in memory...
70
71         $subscriptions = $this->getSubscriptions();
72         $subscribers   = $this->getSubscribers();
73         $groups        = $this->getGroups();
74         $faves         = $this->getFaves();
75
76         $objs = array_merge($subscriptions, $subscribers, $groups, $faves, $notices);
77
78         // Sort by create date
79
80         usort($objs, 'UserActivityStream::compareObject');
81
82         // We'll keep these around for later, and interleave them into
83         // the output stream with the user's notices.
84         foreach ($objs as $obj) {
85             try {
86                 $this->activities[] = $obj->asActivity();
87             } catch (Exception $e) {
88                 // Continue
89             }
90         }
91     }
92
93     /**
94      * Interleave the pre-sorted subs/groups/faves with the user's
95      * notices, all in reverse chron order.
96      */
97     function renderEntries()
98     {
99         $end = time() + 1;
100         foreach ($this->activities as $act) {
101             $start = $act->time;
102
103             if ($this->outputMode == self::OUTPUT_RAW && $start != $end) {
104                 // In raw mode, we haven't pre-fetched notices.
105                 // Grab the chunks of notices between other activities.
106                 $notices = $this->getNoticesBetween($start, $end);
107                 foreach ($notices as $noticeAct) {
108                     try {
109                         $nact = $noticeAct->asActivity();
110                         $nact->outputTo($this, false, false);
111                     } catch (Exception $e) {
112                         // Continue
113                     }
114                 }
115             }
116
117             // Only show the author sub-element if it's different from default user
118             $act->outputTo($this, false, ($act->actor->id != $this->user->uri));
119
120             $end = $start;
121         }
122
123         if ($this->outputMode == self::OUTPUT_RAW) {
124             // Grab anything after the last pre-sorted activity.
125             $notices = $this->getNoticesBetween(0, $end);
126             foreach ($notices as $noticeAct) {
127                 try {
128                     $nact = $noticeAct->asActivity();
129                     $nact->outputTo($this, false, false);
130                 } catch (Exception $e) {
131                     // Continue
132                 }
133             }
134         }
135     }
136
137     function compareObject($a, $b)
138     {
139         $ac = strtotime((empty($a->created)) ? $a->modified : $a->created);
140         $bc = strtotime((empty($b->created)) ? $b->modified : $b->created);
141
142         return (($ac == $bc) ? 0 : (($ac < $bc) ? 1 : -1));
143     }
144
145     function getSubscriptions()
146     {
147         $subs = array();
148
149         $sub = new Subscription();
150
151         $sub->subscriber = $this->user->id;
152
153         if ($sub->find()) {
154             while ($sub->fetch()) {
155                 if ($sub->subscribed != $this->user->id) {
156                     $subs[] = clone($sub);
157                 }
158             }
159         }
160
161         return $subs;
162     }
163
164     function getSubscribers()
165     {
166         $subs = array();
167
168         $sub = new Subscription();
169
170         $sub->subscribed = $this->user->id;
171
172         if ($sub->find()) {
173             while ($sub->fetch()) {
174                 if ($sub->subscriber != $this->user->id) {
175                     $subs[] = clone($sub);
176                 }
177             }
178         }
179
180         return $subs;
181     }
182
183     function getFaves()
184     {
185         $faves = array();
186
187         $fave = new Fave();
188
189         $fave->user_id = $this->user->id;
190
191         if ($fave->find()) {
192             while ($fave->fetch()) {
193                 $faves[] = clone($fave);
194             }
195         }
196
197         return $faves;
198     }
199
200     /**
201      *
202      * @param int $start unix timestamp for earliest
203      * @param int $end unix timestamp for latest
204      * @return array of Notice objects
205      */
206     function getNoticesBetween($start=0, $end=0)
207     {
208         $notices = array();
209
210         $notice = new Notice();
211
212         $notice->profile_id = $this->user->id;
213
214         if ($start) {
215             $tsstart = common_sql_date($start);
216             $notice->whereAdd("created >= '$tsstart'");
217         }
218         if ($end) {
219             $tsend = common_sql_date($end);
220             $notice->whereAdd("created < '$tsend'");
221         }
222
223         $notice->orderBy('created DESC');
224
225         if ($notice->find()) {
226             while ($notice->fetch()) {
227                 $notices[] = clone($notice);
228             }
229         }
230
231         return $notices;
232     }
233
234     function getNotices()
235     {
236         return $this->getNoticesBetween();
237     }
238
239     function getGroups()
240     {
241         $groups = array();
242
243         $gm = new Group_member();
244
245         $gm->profile_id = $this->user->id;
246
247         if ($gm->find()) {
248             while ($gm->fetch()) {
249                 $groups[] = clone($gm);
250             }
251         }
252
253         return $groups;
254     }
255 }