From da5bbe8b50226435a1ec7dc34cd4c40c8d024e5e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 6 Mar 2017 05:06:05 -0500 Subject: [PATCH 1/3] Add public_contact() function - Add function to retrieve the public contact id (uid = 0) of the current logged-in user --- boot.php | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/boot.php b/boot.php index b8e9267070..a5774aaad8 100644 --- a/boot.php +++ b/boot.php @@ -1889,11 +1889,35 @@ function goaway($s) { * @return int|bool user id or false */ function local_user() { - if((x($_SESSION,'authenticated')) && (x($_SESSION,'uid'))) + if (x($_SESSION, 'authenticated') && x($_SESSION, 'uid')) { return intval($_SESSION['uid']); + } return false; } +/** + * @brief Returns the public contact id of logged in user or false. + * + * @return int|bool public contact id or false + */ +function public_contact() { + static $public_contact_id = false; + + if (!$public_contact_id && x($_SESSION, 'authenticated')) { + if (x($_SESSION, 'my_address')) { + // Local user + $public_contact_id = intval(get_contact($_SESSION['my_address'], 0)); + } else if (x($_SESSION, 'visitor_home')) { + // Remote user + $public_contact_id = intval(get_contact($_SESSION['visitor_home'], 0)); + } + } else if (!x($_SESSION, 'authenticated')) { + $public_contact_id = false; + } + + return $public_contact_id; +} + /** * @brief Returns contact id of authenticated site visitor or false * From 67ae0fed7fac98b71076e501bf6595cf917d3b13 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 6 Mar 2017 05:07:17 -0500 Subject: [PATCH 2/3] Fix response "self" assigment - Switch from unreliable `uid` matching to `author-id` using public_contact() --- include/conversation.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/conversation.php b/include/conversation.php index a1d086cb9d..93c42cd7b1 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -416,8 +416,8 @@ These Fields are not added below (yet). They are here to for bug search. `item`.`shadow`, */ - return "`item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`, - `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`, + return "`item`.`author-id`, `item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`, + `item`.`owner-id`, `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`, `item`.`contact-id`, `item`.`uid`, `item`.`id`, `item`.`parent`, `item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`commented`, `item`.`created`, `item`.`edited`, @@ -1066,8 +1066,9 @@ function builtin_activity_puller($item, &$conv_responses) { else $conv_responses[$mode][$item['thr-parent']] ++; - if((local_user()) && (local_user() == $item['uid']) && ($item['self'])) + if (public_contact() == $item['author-id']) { $conv_responses[$mode][$item['thr-parent'] . '-self'] = 1; + } $conv_responses[$mode][$item['thr-parent'] . '-l'][] = $url; From 4931ecafbb2bd3cd18a44d3a366c1051f64a08e0 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 6 Mar 2017 05:28:01 -0500 Subject: [PATCH 3/3] Rewriting of do_like() - Fix behavior where event actions had to be performed twice to switch from one to another - Simplify the contact data retrieval - Make sure contact-id, owner-id and author-id are correctly set --- include/like.php | 264 +++++++++++++++++++++++------------------------ 1 file changed, 130 insertions(+), 134 deletions(-) diff --git a/include/like.php b/include/like.php index 210bde6906..a53b90c039 100644 --- a/include/like.php +++ b/include/like.php @@ -18,155 +18,169 @@ require_once("include/diaspora.php"); function do_like($item_id, $verb) { $a = get_app(); - if(! local_user() && ! remote_user()) { + if (! local_user() && ! remote_user()) { return false; } - switch($verb) { + switch ($verb) { case 'like': + $bodyverb = t('%1$s likes %2$s\'s %3$s'); + $activity = ACTIVITY_LIKE; + break; case 'unlike': + $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); $activity = ACTIVITY_LIKE; break; case 'dislike': case 'undislike': + $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); $activity = ACTIVITY_DISLIKE; break; case 'attendyes': case 'unattendyes': + $bodyverb = t('%1$s is attending %2$s\'s %3$s'); $activity = ACTIVITY_ATTEND; break; case 'attendno': case 'unattendno': + $bodyverb = t('%1$s is not attending %2$s\'s %3$s'); $activity = ACTIVITY_ATTENDNO; break; case 'attendmaybe': case 'unattendmaybe': + $bodyverb = t('%1$s may attend %2$s\'s %3$s'); $activity = ACTIVITY_ATTENDMAYBE; break; default: + logger('like: unknown verb ' . $verb . ' for item ' . $item_id); return false; - break; } + // Enable activity toggling instead of on/off + $event_verb_flag = $activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE; + logger('like: verb ' . $verb . ' item ' . $item_id); - $r = q("SELECT * FROM `item` WHERE `id` = '%s' OR `uri` = '%s' LIMIT 1", + // Retrieve item + $items = q("SELECT * FROM `item` WHERE `id` = '%s' OR `uri` = '%s' LIMIT 1", dbesc($item_id), dbesc($item_id) ); - if(! $item_id || (! dbm::is_result($r))) { - logger('like: no item ' . $item_id); + if (! $item_id || ! dbm::is_result($items)) { + logger('like: unknown item ' . $item_id); return false; } - $item = $r[0]; + $item = $items[0]; - $owner_uid = $item['uid']; - - if (! can_write_wall($a,$owner_uid)) { + if (! can_write_wall($a, $item['uid'])) { + logger('like: unable to write on wall ' . $item['uid']); return false; } - $remote_owner = null; + // Retrieves the local post owner + $owners = q("SELECT `contact`.* FROM `contact` + WHERE `contact`.`self` = 1 + AND `contact`.`uid` = %d", + intval($item['uid']) + ); + if (dbm::is_result($owners)) { + $owner_self_contact = $owners[0]; + } else { + logger('like: unknown owner ' . $item['uid']); + return false; + } - if(! $item['wall']) { - // The top level post may have been written by somebody on another system - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($item['contact-id']), - intval($item['uid']) + // Retrieve the current logged in user's public contact + $author_id = public_contact(); + + $contacts = q("SELECT * FROM `contact` WHERE `id` = %d", + intval($author_id) + ); + if (dbm::is_result($contacts)) { + $author_contact = $contacts[0]; + } else { + logger('like: unknown author ' . $author_id); + return false; + } + + // Contact-id is the uid-dependant author contact + if (local_user() == $item['uid']) { + $item_contact_id = $owner_self_contact['id']; + $item_contact = $owner_self_contact; + } else { + $item_contact_id = get_contact($author_contact['url'], $item['uid']); + + $contacts = q("SELECT * FROM `contact` WHERE `id` = %d", + intval($item_contact_id) ); - if (! dbm::is_result($r)) { + if (dbm::is_result($contacts)) { + $item_contact = $contacts[0]; + } else { + logger('like: unknown item contact ' . $item_contact_id); return false; } - if (! $r[0]['self']) { - $remote_owner = $r[0]; - } } - // this represents the post owner on this system. - - $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` - WHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1", - intval($owner_uid) - ); - if (dbm::is_result($r)) { - $owner = $r[0]; - } - - if (! $owner) { - logger('like: no owner'); - return false; - } - - if (! $remote_owner) { - $remote_owner = $owner; - } - - // This represents the person posting - - if ((local_user()) && (local_user() == $owner_uid)) { - $contact = $owner; - } else { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($_SESSION['visitor_id']), - intval($owner_uid) - ); - if (dbm::is_result($r)) { - $contact = $r[0]; - } - } - if (! $contact) { - return false; - } - - - $verbs = " '".dbesc($activity)."' "; - + // Look for an existing verb row // event participation are essentially radio toggles. If you make a subsequent choice, // we need to eradicate your first choice. - if ($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) { - $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' "; + if ($event_verb_flag) { + $verbs = "'" . dbesc(ACTIVITY_ATTEND) . "', '" . dbesc(ACTIVITY_ATTENDNO) . "', '" . dbesc(ACTIVITY_ATTENDMAYBE) . "'"; + } else { + $verbs = "'".dbesc($activity)."'"; } - $r = q("SELECT `id`, `guid` FROM `item` WHERE `verb` IN ( $verbs ) AND `deleted` = 0 - AND `contact-id` = %d AND `uid` = %d - AND (`parent` = '%s' OR `parent-uri` = '%s' OR `thr-parent` = '%s') LIMIT 1", - intval($contact['id']), intval($owner_uid), + $existing_like = q("SELECT `id`, `guid`, `verb` FROM `item` + WHERE `verb` IN ($verbs) + AND `deleted` = 0 + AND `author-id` = %d + AND `uid` = %d + AND (`parent` = '%s' OR `parent-uri` = '%s' OR `thr-parent` = '%s') + LIMIT 1", + intval($author_contact['id']), + intval($item['uid']), dbesc($item_id), dbesc($item_id), dbesc($item['uri']) ); - if (dbm::is_result($r)) { - $like_item = $r[0]; + // If it exists, mark it as deleted + if (dbm::is_result($existing_like)) { + $like_item = $existing_like[0]; // Already voted, undo it - $r = q("UPDATE `item` SET `deleted` = 1, `unseen` = 1, `changed` = '%s' WHERE `id` = %d", + q("UPDATE `item` SET `deleted` = 1, `unseen` = 1, `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), intval($like_item['id']) ); - // Clean up the Diaspora signatures for this like // Go ahead and do it even if Diaspora support is disabled. We still want to clean up // if it had been enabled in the past - $r = q("DELETE FROM `sign` WHERE `iid` = %d", + q("DELETE FROM `sign` WHERE `iid` = %d", intval($like_item['id']) ); $like_item_id = $like_item['id']; proc_run(PRIORITY_HIGH, "include/notifier.php", "like", $like_item_id); + if (!$event_verb_flag || $like_item['verb'] == $activity) { + return true; + } + } + + // Verb is "un-something", just trying to delete existing entries + if (strpos($verb, 'un') === 0) { return true; } - $uri = item_new_uri($a->get_hostname(),$owner_uid); - + // Else or if event verb different from existing row, create a new item row $post_type = (($item['resource-id']) ? t('photo') : t('status')); if ($item['object-type'] === ACTIVITY_OBJ_EVENT) { $post_type = t('event'); } - $objtype = (($item['resource-id']) ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ); - $link = xmlify('' . "\n") ; + $objtype = $item['resource-id'] ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ; + $link = xmlify('' . "\n") ; $body = $item['body']; $obj = <<< EOT @@ -180,80 +194,62 @@ function do_like($item_id, $verb) { $body EOT; - if ($verb === 'like') { - $bodyverb = t('%1$s likes %2$s\'s %3$s'); - } - if ($verb === 'dislike') { - $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); - } - if ($verb === 'attendyes') { - $bodyverb = t('%1$s is attending %2$s\'s %3$s'); - } - if ($verb === 'attendno') { - $bodyverb = t('%1$s is not attending %2$s\'s %3$s'); - } - if ($verb === 'attendmaybe') { - $bodyverb = t('%1$s may attend %2$s\'s %3$s'); - } - if (! isset($bodyverb)) { - return false; - } - - $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; + $ulink = '[url=' . $author_contact['url'] . ']' . $author_contact['name'] . '[/url]'; $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; - $plink = '[url=' . App::get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; + $plink = '[url=' . App::get_baseurl() . '/display/' . $owner_self_contact['nick'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; - /// @TODO Or rewrite this to multi-line initialization of the array? - $arr = array(); + $new_item = array( + 'guid' => get_guid(32), + 'uri' => item_new_uri($a->get_hostname(), $item['uid']), + 'uid' => $item['uid'], + 'contact-id' => $item_contact_id, + 'type' => 'activity', + 'wall' => $item['wall'], + 'origin' => 1, + 'gravity' => GRAVITY_LIKE, + 'parent' => $item['id'], + 'parent-uri' => $item['uri'], + 'thr-parent' => $item['uri'], + 'owner-id' => $item['owner-id'], + 'owner-name' => $item['owner-name'], + 'owner-link' => $item['owner-link'], + 'owner-avatar' => $item['owner-avatar'], + 'author-id' => $author_contact['id'], + 'author-name' => $author_contact['name'], + 'author-link' => $author_contact['url'], + 'author-avatar' => $author_contact['thumb'], + 'body' => sprintf($bodyverb, $ulink, $alink, $plink), + 'verb' => $activity, + 'object-type' => $objtype, + 'object' => $obj, + 'allow_cid' => $item['allow_cid'], + 'allow_gid' => $item['allow_gid'], + 'deny_cid' => $item['deny_cid'], + 'deny_gid' => $item['deny_gid'], + 'visible' => 1, + 'unseen' => 1, + 'last-child' => 0 + ); - $arr['guid'] = get_guid(32); - $arr['uri'] = $uri; - $arr['uid'] = $owner_uid; - $arr['contact-id'] = $contact['id']; - $arr['type'] = 'activity'; - $arr['wall'] = $item['wall']; - $arr['origin'] = 1; - $arr['gravity'] = GRAVITY_LIKE; - $arr['parent'] = $item['id']; - $arr['parent-uri'] = $item['uri']; - $arr['thr-parent'] = $item['uri']; - $arr['owner-name'] = $remote_owner['name']; - $arr['owner-link'] = $remote_owner['url']; - $arr['owner-avatar'] = $remote_owner['thumb']; - $arr['author-name'] = $contact['name']; - $arr['author-link'] = $contact['url']; - $arr['author-avatar'] = $contact['thumb']; - $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); - $arr['verb'] = $activity; - $arr['object-type'] = $objtype; - $arr['object'] = $obj; - $arr['allow_cid'] = $item['allow_cid']; - $arr['allow_gid'] = $item['allow_gid']; - $arr['deny_cid'] = $item['deny_cid']; - $arr['deny_gid'] = $item['deny_gid']; - $arr['visible'] = 1; - $arr['unseen'] = 1; - $arr['last-child'] = 0; - - $post_id = item_store($arr); + $new_item_id = item_store($new_item); + // @todo: Explain this block if (! $item['visible']) { - $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d", + q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d", intval($item['id']), - intval($owner_uid) + intval($item['uid']) ); } - // Save the author information for the like in case we need to relay to Diaspora - Diaspora::store_like_signature($contact, $post_id); + Diaspora::store_like_signature($item_contact, $new_item_id); - $arr['id'] = $post_id; + $new_item['id'] = $new_item_id; - call_hooks('post_local_end', $arr); + call_hooks('post_local_end', $new_item); - proc_run(PRIORITY_HIGH, "include/notifier.php", "like", $post_id); + proc_run(PRIORITY_HIGH, "include/notifier.php", "like", $new_item_id); return true; }