]> git.mxchange.org Git - friendica.git/blob - include/like.php
Scrape: Always take the first alias
[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['guid'] = get_guid(32);
200         $arr['uri'] = $uri;
201         $arr['uid'] = $owner_uid;
202         $arr['contact-id'] = $contact['id'];
203         $arr['type'] = 'activity';
204         $arr['wall'] = $item['wall'];
205         $arr['origin'] = 1;
206         $arr['gravity'] = GRAVITY_LIKE;
207         $arr['parent'] = $item['id'];
208         $arr['parent-uri'] = $item['uri'];
209         $arr['thr-parent'] = $item['uri'];
210         $arr['owner-name'] = $remote_owner['name'];
211         $arr['owner-link'] = $remote_owner['url'];
212         $arr['owner-avatar'] = $remote_owner['thumb'];
213         $arr['author-name'] = $contact['name'];
214         $arr['author-link'] = $contact['url'];
215         $arr['author-avatar'] = $contact['thumb'];
216
217         $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
218         $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
219         $plink = '[url=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]';
220         $arr['body'] =  sprintf( $bodyverb, $ulink, $alink, $plink );
221
222         $arr['verb'] = $activity;
223         $arr['object-type'] = $objtype;
224         $arr['object'] = $obj;
225         $arr['allow_cid'] = $item['allow_cid'];
226         $arr['allow_gid'] = $item['allow_gid'];
227         $arr['deny_cid'] = $item['deny_cid'];
228         $arr['deny_gid'] = $item['deny_gid'];
229         $arr['visible'] = 1;
230         $arr['unseen'] = 1;
231         $arr['last-child'] = 0;
232
233         $post_id = item_store($arr);
234
235         if(! $item['visible']) {
236                 $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d",
237                         intval($item['id']),
238                         intval($owner_uid)
239                 );
240         }
241
242
243         // Save the author information for the like in case we need to relay to Diaspora
244         store_diaspora_like_sig($activity, $post_type, $contact, $post_id);
245
246         $arr['id'] = $post_id;
247
248         call_hooks('post_local_end', $arr);
249
250         proc_run('php',"include/notifier.php","like","$post_id");
251
252         return true;
253 }
254
255
256
257 function store_diaspora_like_retract_sig($activity, $item, $like_item, $contact) {
258         // Note that we can only create a signature for a user of the local server. We don't have
259         // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
260         // means we are the relay, and for relayable_retractions, Diaspora
261         // only checks the parent_author_signature if it doesn't have to relay further
262         //
263         // If $item['resource-id'] exists, it means the item is a photo. Diaspora doesn't support
264         // likes on photos, so don't bother.
265
266         $enabled = intval(get_config('system','diaspora_enabled'));
267         if(! $enabled) {
268                 logger('mod_like: diaspora support disabled, not storing like retraction signature', LOGGER_DEBUG);
269                 return;
270         }
271
272         logger('mod_like: storing diaspora like retraction signature');
273
274         if(($activity === ACTIVITY_LIKE) && (! $item['resource-id'])) {
275                 $signed_text = $like_item['guid'] . ';' . 'Like';
276
277                 // Only works for NETWORK_DFRN
278                 $contact_baseurl_start = strpos($contact['url'],'://') + 3;
279                 $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start;
280                 $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
281                 $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
282
283                 // This code could never had worked (the return values form the queries were used in a wrong way.
284                 // Additionally it is needlessly complicated. Either the contact is owner or not. And we have this data already.
285 /*
286                 // Get contact's private key if he's a user of the local Friendica server
287                 $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1",
288                         dbesc($contact['url'])
289                 );
290
291                 if( $r) {
292                         $contact_uid = $r['uid'];
293                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
294                                 intval($contact_uid)
295                         );
296 */
297                 // Is the contact the owner? Then fetch the private key
298                 if ($contact['self'] AND ($contact['uid'] > 0)) {
299                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
300                                 intval($contact['uid'])
301                         );
302
303                         if($r)
304                                 $authorsig = base64_encode(rsa_sign($signed_text,$r[0]['prvkey'],'sha256'));
305                 }
306
307                 if(! isset($authorsig))
308                         $authorsig = '';
309
310                 q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
311                         intval($like_item['id']),
312                         dbesc($signed_text),
313                         dbesc($authorsig),
314                         dbesc($diaspora_handle)
315                 );
316         }
317
318         return;
319 }
320
321 function store_diaspora_like_sig($activity, $post_type, $contact, $post_id) {
322         // Note that we can only create a signature for a user of the local server. We don't have
323         // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
324         // means we are the relay, and for relayable_retractions, Diaspora
325         // only checks the parent_author_signature if it doesn't have to relay further
326
327         $enabled = intval(get_config('system','diaspora_enabled'));
328         if(! $enabled) {
329                 logger('mod_like: diaspora support disabled, not storing like signature', LOGGER_DEBUG);
330                 return;
331         }
332
333         logger('mod_like: storing diaspora like signature');
334
335         if(($activity === ACTIVITY_LIKE) && ($post_type === t('status'))) {
336                 // Only works for NETWORK_DFRN
337                 $contact_baseurl_start = strpos($contact['url'],'://') + 3;
338                 $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start;
339                 $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
340                 $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
341
342
343                 // This code could never had worked (the return values form the queries were used in a wrong way.
344                 // Additionally it is needlessly complicated. Either the contact is owner or not. And we have this data already.
345 /*
346                 // Get contact's private key if he's a user of the local Friendica server
347                 $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1",
348                         dbesc($contact['url'])
349                 );
350
351                 if( $r) {
352                         $contact_uid = $r['uid'];
353                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
354                                 intval($contact_uid)
355                         );
356
357                         if( $r)
358                                 $contact_uprvkey = $r['prvkey'];
359                 }
360 */
361
362                 // Is the contact the owner? Then fetch the private key
363                 if ($contact['self'] AND ($contact['uid'] > 0)) {
364                         $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1",
365                                 intval($contact['uid'])
366                         );
367
368                         if($r)
369                                 $contact_uprvkey = $r[0]['prvkey'];
370                 }
371
372                 $r = q("SELECT guid, parent FROM `item` WHERE id = %d LIMIT 1",
373                         intval($post_id)
374                 );
375                 if( $r) {
376                         $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1",
377                                 intval($r[0]['parent']),
378                                 intval($r[0]['parent'])
379                         );
380                         if( $p) {
381                                 $signed_text = 'true;'.$r[0]['guid'].';Post;'.$p[0]['guid'].';'.$diaspora_handle;
382
383                                 if(isset($contact_uprvkey))
384                                         $authorsig = base64_encode(rsa_sign($signed_text,$contact_uprvkey,'sha256'));
385                                 else
386                                         $authorsig = '';
387
388                                 q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
389                                         intval($post_id),
390                                         dbesc($signed_text),
391                                         dbesc($authorsig),
392                                         dbesc($diaspora_handle)
393                                 );
394                         }
395                 }
396         }
397
398         return;
399 }