diff --git a/include/api.php b/include/api.php index f5747ad1c..4edced221 100644 --- a/include/api.php +++ b/include/api.php @@ -48,7 +48,6 @@ require_once 'include/security.php'; require_once 'include/html2bbcode.php'; require_once 'mod/wall_upload.php'; require_once 'mod/proxy.php'; -require_once 'include/like.php'; define('API_METHOD_ANY', '*'); define('API_METHOD_GET', 'GET'); @@ -5587,7 +5586,7 @@ function api_friendica_activity($type) $id = (x($_REQUEST, 'id') ? $_REQUEST['id'] : 0); - $res = do_like($id, $verb); + $res = Item::performLike($id, $verb); if ($res) { if ($type == "xml") { diff --git a/include/like.php b/include/like.php deleted file mode 100644 index 7e24b463c..000000000 --- a/include/like.php +++ /dev/null @@ -1,267 +0,0 @@ - ID of posted item - */ -function do_like($item_id, $verb) { - $a = get_app(); - - if (!local_user() && !remote_user()) { - return false; - } - - switch ($verb) { - case 'like': - $bodyverb = L10n::t('%1$s likes %2$s\'s %3$s'); - $activity = ACTIVITY_LIKE; - break; - case 'unlike': - $bodyverb = L10n::t('%1$s doesn\'t like %2$s\'s %3$s'); - $activity = ACTIVITY_LIKE; - break; - case 'dislike': - case 'undislike': - $bodyverb = L10n::t('%1$s doesn\'t like %2$s\'s %3$s'); - $activity = ACTIVITY_DISLIKE; - break; - case 'attendyes': - case 'unattendyes': - $bodyverb = L10n::t('%1$s is attending %2$s\'s %3$s'); - $activity = ACTIVITY_ATTEND; - break; - case 'attendno': - case 'unattendno': - $bodyverb = L10n::t('%1$s is not attending %2$s\'s %3$s'); - $activity = ACTIVITY_ATTENDNO; - break; - case 'attendmaybe': - case 'unattendmaybe': - $bodyverb = L10n::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; - } - - // 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); - - // 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($items)) { - logger('like: unknown item ' . $item_id); - return false; - } - - $item = $items[0]; - $uid = $item['uid']; - - if (($uid == 0) && local_user()) { - $uid = local_user(); - } - - if (!can_write_wall($uid)) { - logger('like: unable to write on wall ' . $uid); - return false; - } - - // Retrieves the local post owner - $owners = q("SELECT `contact`.* FROM `contact` - WHERE `contact`.`self` - AND `contact`.`uid` = %d", - intval($uid) - ); - if (DBM::is_result($owners)) { - $owner_self_contact = $owners[0]; - } else { - logger('like: unknown owner ' . $uid); - return false; - } - - // 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() == $uid) { - $item_contact_id = $owner_self_contact['id']; - $item_contact = $owner_self_contact; - } else { - $item_contact_id = Contact::getIdForURL($author_contact['url'], $uid); - - $contacts = q("SELECT * FROM `contact` WHERE `id` = %d", - intval($item_contact_id) - ); - if (DBM::is_result($contacts)) { - $item_contact = $contacts[0]; - } else { - logger('like: unknown item contact ' . $item_contact_id); - return false; - } - } - - // 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 ($event_verb_flag) { - $verbs = "'" . dbesc(ACTIVITY_ATTEND) . "', '" . dbesc(ACTIVITY_ATTENDNO) . "', '" . dbesc(ACTIVITY_ATTENDMAYBE) . "'"; - } else { - $verbs = "'".dbesc($activity)."'"; - } - - $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 it exists, mark it as deleted - if (DBM::is_result($existing_like)) { - $like_item = $existing_like[0]; - - // Already voted, undo it - 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 - dba::delete('sign', ['iid' => $like_item['id']]); - - $like_item_id = $like_item['id']; - Worker::add(PRIORITY_HIGH, "Notifier", "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; - } - - // Else or if event verb different from existing row, create a new item row - $post_type = (($item['resource-id']) ? L10n::t('photo') : L10n::t('status')); - if ($item['object-type'] === ACTIVITY_OBJ_EVENT) { - $post_type = L10n::t('event'); - } - $objtype = $item['resource-id'] ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ; - $link = xmlify('' . "\n") ; - $body = $item['body']; - - $obj = <<< EOT - - - $objtype - 1 - {$item['uri']} - $link - - $body - -EOT; - - $ulink = '[url=' . $author_contact['url'] . ']' . $author_contact['name'] . '[/url]'; - $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; - $plink = '[url=' . System::baseUrl() . '/display/' . $owner_self_contact['nick'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; - - $new_item = [ - '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, - ]; - - $new_item_id = Item::insert($new_item); - - // @todo: Explain this block - if (! $item['visible']) { - q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", - intval($item['id']) - ); - } - - // Save the author information for the like in case we need to relay to Diaspora - Diaspora::storeLikeSignature($item_contact, $new_item_id); - - $new_item['id'] = $new_item_id; - - Addon::callHooks('post_local_end', $new_item); - - Worker::add(PRIORITY_HIGH, "Notifier", "like", $new_item_id); - - return true; -} diff --git a/mod/like.php b/mod/like.php index 3c7e70cea..9371c3074 100644 --- a/mod/like.php +++ b/mod/like.php @@ -2,11 +2,11 @@ use Friendica\App; use Friendica\Core\System; +use Friendica\Model\Item; require_once 'include/security.php'; require_once 'include/bbcode.php'; require_once 'include/items.php'; -require_once 'include/like.php'; function like_content(App $a) { if (!local_user() && !remote_user()) { @@ -22,7 +22,7 @@ function like_content(App $a) { $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); - $r = do_like($item_id, $verb); + $r = Item::performLike($item_id, $verb); if (!$r) { return; } diff --git a/src/Model/Item.php b/src/Model/Item.php index 98ffd89ff..754537518 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -6,28 +6,32 @@ namespace Friendica\Model; +use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\L10n; use Friendica\Core\PConfig; -use Friendica\Core\Worker; use Friendica\Core\System; +use Friendica\Core\Worker; +use Friendica\Database\DBM; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\GContact; use Friendica\Model\Group; use Friendica\Model\Term; -use Friendica\Model\User; -use Friendica\Database\DBM; +use Friendica\Object\Image; +use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use dba; use Text_LanguageDetect; +require_once 'boot.php'; require_once 'include/tags.php'; require_once 'include/threads.php'; require_once 'include/items.php'; require_once 'include/text.php'; -class Item +class Item extends BaseObject { /** * @brief Update existing item entries @@ -1642,4 +1646,230 @@ class Item } return false; } + + /** + * @brief add/remove activity to an item + * + * Toggle activities as like,dislike,attend of an item + * + * @param string $item_id + * @param string $verb + * Activity verb. One of + * like, unlike, dislike, undislike, attendyes, unattendyes, + * attendno, unattendno, attendmaybe, unattendmaybe + * @hook 'post_local_end' + * array $arr + * 'post_id' => ID of posted item + */ + public static function performLike($item_id, $verb) + { + if (!local_user() && !remote_user()) { + return false; + } + + switch ($verb) { + case 'like': + case 'unlike': + $bodyverb = L10n::t('%1$s likes %2$s\'s %3$s'); + $activity = ACTIVITY_LIKE; + break; + case 'dislike': + case 'undislike': + $bodyverb = L10n::t('%1$s doesn\'t like %2$s\'s %3$s'); + $activity = ACTIVITY_DISLIKE; + break; + case 'attendyes': + case 'unattendyes': + $bodyverb = L10n::t('%1$s is attending %2$s\'s %3$s'); + $activity = ACTIVITY_ATTEND; + break; + case 'attendno': + case 'unattendno': + $bodyverb = L10n::t('%1$s is not attending %2$s\'s %3$s'); + $activity = ACTIVITY_ATTENDNO; + break; + case 'attendmaybe': + case 'unattendmaybe': + $bodyverb = L10n::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; + } + + // 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); + + $item = dba::selectFirst('item', [], ['`id` = ? OR `uri` = ?', $item_id, $item_id]); + if (!DBM::is_result($item)) { + logger('like: unknown item ' . $item_id); + return false; + } + + $uid = $item['uid']; + if (($uid == 0) && local_user()) { + $uid = local_user(); + } + + if (!can_write_wall($uid)) { + logger('like: unable to write on wall ' . $uid); + return false; + } + + // Retrieves the local post owner + $owner_self_contact = dba::selectFirst('contact', [], ['uid' => $uid, 'self' => true]); + if (!DBM::is_result($owner_self_contact)) { + logger('like: unknown owner ' . $uid); + return false; + } + + // Retrieve the current logged in user's public contact + $author_id = public_contact(); + + $author_contact = dba::selectFirst('contact', [], ['id' => $author_id]); + if (!DBM::is_result($author_contact)) { + logger('like: unknown author ' . $author_id); + return false; + } + + // Contact-id is the uid-dependant author contact + if (local_user() == $uid) { + $item_contact_id = $owner_self_contact['id']; + $item_contact = $owner_self_contact; + } else { + $item_contact_id = Contact::getIdForURL($author_contact['url'], $uid); + $item_contact = dba::selectFirst('contact', [], ['id' => $item_contact_id]); + if (!DBM::is_result($item_contact)) { + logger('like: unknown item contact ' . $item_contact_id); + return false; + } + } + + // 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 ($event_verb_flag) { + $verbs = "'" . dbesc(ACTIVITY_ATTEND) . "', '" . dbesc(ACTIVITY_ATTENDNO) . "', '" . dbesc(ACTIVITY_ATTENDMAYBE) . "'"; + } else { + $verbs = "'".dbesc($activity)."'"; + } + + $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 it exists, mark it as deleted + if (DBM::is_result($existing_like)) { + $like_item = $existing_like[0]; + + // Already voted, undo it + $fields = ['deleted' => true, 'unseen' => true, 'changed' => datetime_convert()]; + dba::update('item', $fields, ['id' => $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 + dba::delete('sign', ['iid' => $like_item['id']]); + + $like_item_id = $like_item['id']; + Worker::add(PRIORITY_HIGH, "Notifier", "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; + } + + // Else or if event verb different from existing row, create a new item row + $post_type = (($item['resource-id']) ? L10n::t('photo') : L10n::t('status')); + if ($item['object-type'] === ACTIVITY_OBJ_EVENT) { + $post_type = L10n::t('event'); + } + $objtype = $item['resource-id'] ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ; + $link = xmlify('' . "\n") ; + $body = $item['body']; + + $obj = <<< EOT + + + $objtype + 1 + {$item['uri']} + $link + + $body + +EOT; + + $ulink = '[url=' . $author_contact['url'] . ']' . $author_contact['name'] . '[/url]'; + $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; + $plink = '[url=' . System::baseUrl() . '/display/' . $owner_self_contact['nick'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; + + $new_item = [ + 'guid' => get_guid(32), + 'uri' => item_new_uri(self::getApp()->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, + ]; + + $new_item_id = Item::insert($new_item); + + // @todo: Explain this block + if (! $item['visible']) { + q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", + intval($item['id']) + ); + } + + // Save the author information for the like in case we need to relay to Diaspora + Diaspora::storeLikeSignature($item_contact, $new_item_id); + + $new_item['id'] = $new_item_id; + + Addon::callHooks('post_local_end', $new_item); + + Worker::add(PRIORITY_HIGH, "Notifier", "like", $new_item_id); + + return true; + } }