]> git.mxchange.org Git - friendica.git/blob - include/like.php
Merge pull request #2251 from annando/1601-plaintext
[friendica.git] / include / like.php
1 <?php
2
3 /**
4  * @brief add/remove activity to an item
5  *
6  * Toggle activities as like,dislike,attend of an item
7  *
8  * @param string $item_id
9  * @param string $verb
10  *              Activity verb. One of
11  *                      like, unlike, dislike, undislike, attendyes, unattendyes,
12  *                      attendno, unattendno, attendmaybe, unattendmaybe
13  * @hook 'post_local_end'
14  *              array $arr
15  *                      'post_id' => ID of posted item
16  */
17 function do_like($item_id, $verb) {
18         $a = get_app();
19
20         if(! local_user() && ! remote_user()) {
21                 return false;
22         }
23
24         switch($verb) {
25                 case 'like':
26                 case 'unlike':
27                         $activity = ACTIVITY_LIKE;
28                         break;
29                 case 'dislike':
30                 case 'undislike':
31                         $activity = ACTIVITY_DISLIKE;
32                         break;
33                 case 'attendyes':
34                 case 'unattendyes':
35                         $activity = ACTIVITY_ATTEND;
36                         break;
37                 case 'attendno':
38                 case 'unattendno':
39                         $activity = ACTIVITY_ATTENDNO;
40                         break;
41                 case 'attendmaybe':
42                 case 'unattendmaybe':
43                         $activity = ACTIVITY_ATTENDMAYBE;
44                         break;
45                 default:
46                         return false;
47                         break;
48         }
49
50
51         logger('like: verb ' . $verb . ' item ' . $item_id);
52
53
54         $r = q("SELECT * FROM `item` WHERE `id` = '%s' OR `uri` = '%s' LIMIT 1",
55                 dbesc($item_id),
56                 dbesc($item_id)
57         );
58
59         if(! $item_id || (! count($r))) {
60                 logger('like: no item ' . $item_id);
61                 return false;
62         }
63
64         $item = $r[0];
65
66         $owner_uid = $item['uid'];
67
68         if(! can_write_wall($a,$owner_uid)) {
69                 return false;
70         }
71
72         $remote_owner = null;
73
74         if(! $item['wall']) {
75                 // The top level post may have been written by somebody on another system
76                 $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
77                         intval($item['contact-id']),
78                         intval($item['uid'])
79                 );
80                 if(! count($r))
81                         return false;
82                 if(! $r[0]['self'])
83                         $remote_owner = $r[0];
84         }
85
86         // this represents the post owner on this system.
87
88         $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`
89                 WHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1",
90                 intval($owner_uid)
91         );
92         if(count($r))
93                 $owner = $r[0];
94
95         if(! $owner) {
96                 logger('like: no owner');
97                 return false;
98         }
99
100         if(! $remote_owner)
101                 $remote_owner = $owner;
102
103
104         // This represents the person posting
105
106         if((local_user()) && (local_user() == $owner_uid)) {
107                 $contact = $owner;
108         }
109         else {
110                 $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
111                         intval($_SESSION['visitor_id']),
112                         intval($owner_uid)
113                 );
114                 if(count($r))
115                         $contact = $r[0];
116         }
117         if(! $contact) {
118                 return false;
119         }
120
121
122         $verbs = " '".dbesc($activity)."' ";
123
124         // event participation are essentially radio toggles. If you make a subsequent choice,
125         // we need to eradicate your first choice.
126         if($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) {
127                 $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
128         }
129
130         $r = q("SELECT `id`, `guid` FROM `item` WHERE `verb` IN ( $verbs ) AND `deleted` = 0
131                 AND `contact-id` = %d AND `uid` = %d
132                 AND (`parent` = '%s' OR `parent-uri` = '%s' OR `thr-parent` = '%s') LIMIT 1",
133                 intval($contact['id']), intval($owner_uid),
134                 dbesc($item_id), dbesc($item_id), dbesc($item['uri'])
135         );
136
137         if(count($r)) {
138                 $like_item = $r[0];
139
140                 // Already voted, undo it
141                 $r = q("UPDATE `item` SET `deleted` = 1, `unseen` = 1, `changed` = '%s' WHERE `id` = %d",
142                         dbesc(datetime_convert()),
143                         intval($like_item['id'])
144                 );
145
146
147                 // Clean up the Diaspora signatures for this like
148                 // Go ahead and do it even if Diaspora support is disabled. We still want to clean up
149                 // if it had been enabled in the past
150                 $r = q("DELETE FROM `sign` WHERE `iid` = %d",
151                         intval($like_item['id'])
152                 );
153
154                 // Save the author information for the unlike in case we need to relay to Diaspora
155                 store_diaspora_like_retract_sig($activity, $item, $like_item, $contact);
156
157                 $like_item_id = $like_item['id'];
158                 proc_run('php',"include/notifier.php","like","$like_item_id");
159
160                 return true;
161         }
162
163         $uri = item_new_uri($a->get_hostname(),$owner_uid);
164
165         $post_type = (($item['resource-id']) ? t('photo') : t('status'));
166         if($item['obj_type'] === ACTIVITY_OBJ_EVENT)
167                 $post_type = t('event');
168         $objtype = (($item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
169         $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n") ;
170         $body = $item['body'];
171
172         $obj = <<< EOT
173
174         <object>
175                 <type>$objtype</type>
176                 <local>1</local>
177                 <id>{$item['uri']}</id>
178                 <link>$link</link>
179                 <title></title>
180                 <content>$body</content>
181         </object>
182 EOT;
183         if($verb === 'like')
184                 $bodyverb = t('%1$s likes %2$s\'s %3$s');
185         if($verb === 'dislike')
186                 $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
187         if($verb === 'attendyes')
188                 $bodyverb = t('%1$s is attending %2$s\'s %3$s');
189         if($verb === 'attendno')
190                 $bodyverb = t('%1$s is not attending %2$s\'s %3$s');
191         if($verb === 'attendmaybe')
192                 $bodyverb = t('%1$s may attend %2$s\'s %3$s');
193
194         if(! isset($bodyverb))
195                         return false;
196
197         $arr = array();
198
199         $arr['uri'] = $uri;
200         $arr['uid'] = $owner_uid;
201         $arr['contact-id'] = $contact['id'];
202         $arr['type'] = 'activity';
203         $arr['wall'] = $item['wall'];
204         $arr['origin'] = 1;
205         $arr['gravity'] = GRAVITY_LIKE;
206         $arr['parent'] = $item['id'];
207         $arr['parent-uri'] = $item['uri'];
208         $arr['thr-parent'] = $item['uri'];
209         $arr['owner-name'] = $remote_owner['name'];
210         $arr['owner-link'] = $remote_owner['url'];
211         $arr['owner-avatar'] = $remote_owner['thumb'];
212         $arr['author-name'] = $contact['name'];
213         $arr['author-link'] = $contact['url'];
214         $arr['author-avatar'] = $contact['thumb'];
215
216         $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
217         $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
218         $plink = '[url=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]';
219         $arr['body'] =  sprintf( $bodyverb, $ulink, $alink, $plink );
220
221         $arr['verb'] = $activity;
222         $arr['object-type'] = $objtype;
223         $arr['object'] = $obj;
224         $arr['allow_cid'] = $item['allow_cid'];
225         $arr['allow_gid'] = $item['allow_gid'];
226         $arr['deny_cid'] = $item['deny_cid'];
227         $arr['deny_gid'] = $item['deny_gid'];
228         $arr['visible'] = 1;
229         $arr['unseen'] = 1;
230         $arr['last-child'] = 0;
231
232         $post_id = item_store($arr);
233
234         if(! $item['visible']) {
235                 $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d",
236                         intval($item['id']),
237                         intval($owner_uid)
238                 );
239         }
240
241
242         // Save the author information for the like in case we need to relay to Diaspora
243         store_diaspora_like_sig($activity, $post_type, $contact, $post_id);
244
245         $arr['id'] = $post_id;
246
247         call_hooks('post_local_end', $arr);
248
249         proc_run('php',"include/notifier.php","like","$post_id");
250
251         return true;
252 }
253
254
255
256 function store_diaspora_like_retract_sig($activity, $item, $like_item, $contact) {
257         // Note that we can only create a signature for a user of the local server. We don't have
258         // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
259         // means we are the relay, and for relayable_retractions, Diaspora
260         // only checks the parent_author_signature if it doesn't have to relay further
261         //
262         // If $item['resource-id'] exists, it means the item is a photo. Diaspora doesn't support
263         // likes on photos, so don't bother.
264
265         $enabled = intval(get_config('system','diaspora_enabled'));
266         if(! $enabled) {
267                 logger('mod_like: diaspora support disabled, not storing like retraction signature', LOGGER_DEBUG);
268                 return;
269         }
270
271         logger('mod_like: storing diaspora like retraction signature');
272
273         if(($activity === ACTIVITY_LIKE) && (! $item['resource-id'])) {
274                 $signed_text = $like_item['guid'] . ';' . 'Like';
275
276                 // Only works for NETWORK_DFRN
277                 $contact_baseurl_start = strpos($contact['url'],'://') + 3;
278                 $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start;
279                 $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
280                 $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
281
282                 // Get contact's private key if he's a user of the local Friendica server
283                 $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1",
284                         dbesc($contact['url'])
285                 );
286
287                 if( $r) {
288                         $contact_uid = $r['uid'];
289                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
290                                 intval($contact_uid)
291                         );
292
293                         if( $r)
294                                 $authorsig = base64_encode(rsa_sign($signed_text,$r['prvkey'],'sha256'));
295                 }
296
297                 if(! isset($authorsig))
298                         $authorsig = '';
299
300                 q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
301                         intval($like_item['id']),
302                         dbesc($signed_text),
303                         dbesc($authorsig),
304                         dbesc($diaspora_handle)
305                 );
306         }
307
308         return;
309 }
310
311 function store_diaspora_like_sig($activity, $post_type, $contact, $post_id) {
312         // Note that we can only create a signature for a user of the local server. We don't have
313         // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
314         // means we are the relay, and for relayable_retractions, Diaspora
315         // only checks the parent_author_signature if it doesn't have to relay further
316
317         $enabled = intval(get_config('system','diaspora_enabled'));
318         if(! $enabled) {
319                 logger('mod_like: diaspora support disabled, not storing like signature', LOGGER_DEBUG);
320                 return;
321         }
322
323         logger('mod_like: storing diaspora like signature');
324
325         if(($activity === ACTIVITY_LIKE) && ($post_type === t('status'))) {
326                 // Only works for NETWORK_DFRN
327                 $contact_baseurl_start = strpos($contact['url'],'://') + 3;
328                 $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start;
329                 $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
330                 $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
331
332                 // Get contact's private key if he's a user of the local Friendica server
333                 $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1",
334                         dbesc($contact['url'])
335                 );
336
337                 if( $r) {
338                         $contact_uid = $r['uid'];
339                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
340                                 intval($contact_uid)
341                         );
342
343                         if( $r)
344                                 $contact_uprvkey = $r['prvkey'];
345                 }
346
347                 $r = q("SELECT guid, parent FROM `item` WHERE id = %d LIMIT 1",
348                         intval($post_id)
349                 );
350                 if( $r) {
351                         $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1",
352                                 intval($r[0]['parent']),
353                                 intval($r[0]['parent'])
354                         );
355                         if( $p) {
356                                 $signed_text = $r[0]['guid'] . ';Post;' . $p[0]['guid'] . ';true;' . $diaspora_handle;
357
358                                 if(isset($contact_uprvkey))
359                                         $authorsig = base64_encode(rsa_sign($signed_text,$contact_uprvkey,'sha256'));
360                                 else
361                                         $authorsig = '';
362
363                                 q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
364                                         intval($post_id),
365                                         dbesc($signed_text),
366                                         dbesc($authorsig),
367                                         dbesc($diaspora_handle)
368                                 );
369                         }
370                 }
371         }
372
373         return;
374 }