]> git.mxchange.org Git - friendica.git/blobdiff - src/Model/Item.php
Move Temporal::convert() to DateTimeFormat::convert()
[friendica.git] / src / Model / Item.php
index ebfca310860c946df093ac2679f6612f15de7d8b..818c4085f715e904ea88ce8411623a0aeec97ef2 100644 (file)
@@ -6,28 +6,34 @@
 
 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 Friendica\Util\DateTimeFormat;
+use Friendica\Util\Temporal;
 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
@@ -144,7 +150,7 @@ class Item
 
                // Set the item to "deleted"
                dba::update('item', ['deleted' => true, 'title' => '', 'body' => '',
-                                       'edited' => datetime_convert(), 'changed' => datetime_convert()],
+                                       'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()],
                                ['id' => $item['id']]);
 
                create_tags_from_item($item['id']);
@@ -204,8 +210,8 @@ class Item
                        $guid_prefix = hash("crc32", $parsed["host"]);
                }
 
-               $arr['guid']          = ((x($arr, 'guid'))          ? notags(trim($arr['guid']))          : get_guid(32, $guid_prefix));
-               $arr['uri']           = ((x($arr, 'uri'))           ? notags(trim($arr['uri']))           : item_new_uri($a->get_hostname(), $uid, $arr['guid']));
+               $arr['guid'] = notags(trim(defaults($arr, 'guid', get_guid(32, $guid_prefix))));
+               $arr['uri'] = notags(trim(defaults($arr, 'uri', item_new_uri($a->get_hostname(), $uid, $arr['guid']))));
 
                // Store conversation data
                $arr = Conversation::insert($arr);
@@ -242,9 +248,7 @@ class Item
                        $arr['gravity'] = 6;   // extensible catchall
                }
 
-               if (!x($arr, 'type')) {
-                       $arr['type']      = 'remote';
-               }
+               $arr['type'] = defaults($arr, 'type', 'remote');
 
                $uid = intval($arr['uid']);
 
@@ -290,47 +294,47 @@ class Item
 
                self::addLanguageInPostopts($arr);
 
-               $arr['wall']          = ((x($arr, 'wall'))          ? intval($arr['wall'])                : 0);
-               $arr['extid']         = ((x($arr, 'extid'))         ? notags(trim($arr['extid']))         : '');
-               $arr['author-name']   = ((x($arr, 'author-name'))   ? trim($arr['author-name'])   : '');
-               $arr['author-link']   = ((x($arr, 'author-link'))   ? notags(trim($arr['author-link']))   : '');
-               $arr['author-avatar'] = ((x($arr, 'author-avatar')) ? notags(trim($arr['author-avatar'])) : '');
-               $arr['owner-name']    = ((x($arr, 'owner-name'))    ? trim($arr['owner-name'])    : '');
-               $arr['owner-link']    = ((x($arr, 'owner-link'))    ? notags(trim($arr['owner-link']))    : '');
-               $arr['owner-avatar']  = ((x($arr, 'owner-avatar'))  ? notags(trim($arr['owner-avatar']))  : '');
-               $arr['received']      = ((x($arr, 'received') !== false) ? datetime_convert('UTC','UTC', $arr['received']) : datetime_convert());
-               $arr['created']       = ((x($arr, 'created') !== false) ? datetime_convert('UTC','UTC', $arr['created']) : $arr['received']);
-               $arr['edited']        = ((x($arr, 'edited') !== false) ? datetime_convert('UTC','UTC', $arr['edited']) : $arr['created']);
-               $arr['changed']       = ((x($arr, 'changed') !== false) ? datetime_convert('UTC','UTC', $arr['changed']) : $arr['created']);
-               $arr['commented']     = ((x($arr, 'commented') !== false) ? datetime_convert('UTC','UTC', $arr['commented']) : $arr['created']);
-               $arr['title']         = ((x($arr, 'title'))         ? trim($arr['title'])         : '');
-               $arr['location']      = ((x($arr, 'location'))      ? trim($arr['location'])      : '');
-               $arr['coord']         = ((x($arr, 'coord'))         ? notags(trim($arr['coord']))         : '');
+               $arr['wall']          = intval(defaults($arr, 'wall', 0));
+               $arr['extid']         = trim(defaults($arr, 'extid', ''));
+               $arr['author-name']   = trim(defaults($arr, 'author-name', ''));
+               $arr['author-link']   = trim(defaults($arr, 'author-link', ''));
+               $arr['author-avatar'] = trim(defaults($arr, 'author-avatar', ''));
+               $arr['owner-name']    = trim(defaults($arr, 'owner-name', ''));
+               $arr['owner-link']    = trim(defaults($arr, 'owner-link', ''));
+               $arr['owner-avatar']  = trim(defaults($arr, 'owner-avatar', ''));
+               $arr['received']      = ((x($arr, 'received') !== false) ? Temporal::convert($arr['received']) : Temporal::convert());
+               $arr['created']       = ((x($arr, 'created') !== false) ? Temporal::convert($arr['created']) : $arr['received']);
+               $arr['edited']        = ((x($arr, 'edited') !== false) ? Temporal::convert($arr['edited']) : $arr['created']);
+               $arr['changed']       = ((x($arr, 'changed') !== false) ? Temporal::convert($arr['changed']) : $arr['created']);
+               $arr['commented']     = ((x($arr, 'commented') !== false) ? Temporal::convert($arr['commented']) : $arr['created']);
+               $arr['title']         = trim(defaults($arr, 'title', ''));
+               $arr['location']      = trim(defaults($arr, 'location', ''));
+               $arr['coord']         = trim(defaults($arr, 'coord', ''));
                $arr['visible']       = ((x($arr, 'visible') !== false) ? intval($arr['visible'])         : 1);
                $arr['deleted']       = 0;
-               $arr['parent-uri']    = ((x($arr, 'parent-uri'))    ? notags(trim($arr['parent-uri']))    : $arr['uri']);
-               $arr['verb']          = ((x($arr, 'verb'))          ? notags(trim($arr['verb']))          : '');
-               $arr['object-type']   = ((x($arr, 'object-type'))   ? notags(trim($arr['object-type']))   : '');
-               $arr['object']        = ((x($arr, 'object'))        ? trim($arr['object'])                : '');
-               $arr['target-type']   = ((x($arr, 'target-type'))   ? notags(trim($arr['target-type']))   : '');
-               $arr['target']        = ((x($arr, 'target'))        ? trim($arr['target'])                : '');
-               $arr['plink']         = ((x($arr, 'plink'))         ? notags(trim($arr['plink']))         : '');
-               $arr['allow_cid']     = ((x($arr, 'allow_cid'))     ? trim($arr['allow_cid'])             : '');
-               $arr['allow_gid']     = ((x($arr, 'allow_gid'))     ? trim($arr['allow_gid'])             : '');
-               $arr['deny_cid']      = ((x($arr, 'deny_cid'))      ? trim($arr['deny_cid'])              : '');
-               $arr['deny_gid']      = ((x($arr, 'deny_gid'))      ? trim($arr['deny_gid'])              : '');
-               $arr['private']       = ((x($arr, 'private'))       ? intval($arr['private'])             : 0);
-               $arr['bookmark']      = ((x($arr, 'bookmark'))      ? intval($arr['bookmark'])            : 0);
-               $arr['body']          = ((x($arr, 'body'))          ? trim($arr['body'])                  : '');
-               $arr['tag']           = ((x($arr, 'tag'))           ? notags(trim($arr['tag']))           : '');
-               $arr['attach']        = ((x($arr, 'attach'))        ? notags(trim($arr['attach']))        : '');
-               $arr['app']           = ((x($arr, 'app'))           ? notags(trim($arr['app']))           : '');
-               $arr['origin']        = ((x($arr, 'origin'))        ? intval($arr['origin'])              : 0);
-               $arr['postopts']      = ((x($arr, 'postopts'))      ? trim($arr['postopts'])              : '');
-               $arr['resource-id']   = ((x($arr, 'resource-id'))   ? trim($arr['resource-id'])           : '');
-               $arr['event-id']      = ((x($arr, 'event-id'))      ? intval($arr['event-id'])            : 0);
-               $arr['inform']        = ((x($arr, 'inform'))        ? trim($arr['inform'])                : '');
-               $arr['file']          = ((x($arr, 'file'))          ? trim($arr['file'])                  : '');
+               $arr['parent-uri']    = trim(defaults($arr, 'parent-uri', $arr['uri']));
+               $arr['verb']          = trim(defaults($arr, 'verb', ''));
+               $arr['object-type']   = trim(defaults($arr, 'object-type', ''));
+               $arr['object']        = trim(defaults($arr, 'object', ''));
+               $arr['target-type']   = trim(defaults($arr, 'target-type', ''));
+               $arr['target']        = trim(defaults($arr, 'target', ''));
+               $arr['plink']         = trim(defaults($arr, 'plink', ''));
+               $arr['allow_cid']     = trim(defaults($arr, 'allow_cid', ''));
+               $arr['allow_gid']     = trim(defaults($arr, 'allow_gid', ''));
+               $arr['deny_cid']      = trim(defaults($arr, 'deny_cid', ''));
+               $arr['deny_gid']      = trim(defaults($arr, 'deny_gid', ''));
+               $arr['private']       = intval(defaults($arr, 'private', 0));
+               $arr['bookmark']      = intval(defaults($arr, 'bookmark', 0));
+               $arr['body']          = trim(defaults($arr, 'body', ''));
+               $arr['tag']           = trim(defaults($arr, 'tag', ''));
+               $arr['attach']        = trim(defaults($arr, 'attach', ''));
+               $arr['app']           = trim(defaults($arr, 'app', ''));
+               $arr['origin']        = intval(defaults($arr, 'origin', 0));
+               $arr['postopts']      = trim(defaults($arr, 'postopts', ''));
+               $arr['resource-id']   = trim(defaults($arr, 'resource-id', ''));
+               $arr['event-id']      = intval(defaults($arr, 'event-id', 0));
+               $arr['inform']        = trim(defaults($arr, 'inform', ''));
+               $arr['file']          = trim(defaults($arr, 'file', ''));
 
                // When there is no content then we don't post it
                if ($arr['body'].$arr['title'] == '') {
@@ -338,13 +342,13 @@ class Item
                }
 
                // Items cannot be stored before they happen ...
-               if ($arr['created'] > datetime_convert()) {
-                       $arr['created'] = datetime_convert();
+               if ($arr['created'] > Temporal::convert()) {
+                       $arr['created'] = Temporal::convert();
                }
 
                // We haven't invented time travel by now.
-               if ($arr['edited'] > datetime_convert()) {
-                       $arr['edited'] = datetime_convert();
+               if ($arr['edited'] > Temporal::convert()) {
+                       $arr['edited'] = Temporal::convert();
                }
 
                if (($arr['author-link'] == "") && ($arr['owner-link'] == "")) {
@@ -738,9 +742,9 @@ class Item
                // update the commented timestamp on the parent
                // Only update "commented" if it is really a comment
                if (($arr['verb'] == ACTIVITY_POST) || !Config::get("system", "like_no_comment")) {
-                       dba::update('item', ['commented' => datetime_convert(), 'changed' => datetime_convert()], ['id' => $parent_id]);
+                       dba::update('item', ['commented' => Temporal::convert(), 'changed' => Temporal::convert()], ['id' => $parent_id]);
                } else {
-                       dba::update('item', ['changed' => datetime_convert()], ['id' => $parent_id]);
+                       dba::update('item', ['changed' => Temporal::convert()], ['id' => $parent_id]);
                }
 
                if ($dsprsig) {
@@ -896,7 +900,7 @@ class Item
         *
         * @param integer $itemid Item ID that should be added
         */
-       private static function addShadowPost($itemid)
+       public static function addShadowPost($itemid)
        {
                $item = dba::selectFirst('item', [], ['id' => $itemid]);
                if (!DBM::is_result($item)) {
@@ -1026,7 +1030,8 @@ class Item
         *
         * @param array $arr Contains the just posted item record
         */
-       private static function updateContact($arr) {
+       private static function updateContact($arr)
+       {
                // Unarchive the author
                $contact = dba::selectFirst('contact', [], ['id' => $arr["author-link"]]);
                if ($contact['term-date'] > NULL_DATE) {
@@ -1068,94 +1073,8 @@ class Item
                }
        }
 
-       /**
-        * The purpose of this function is to apply system message length limits to
-        * imported messages without including any embedded photos in the length
-        *
-        * @brief Truncates imported message body string length to max_import_size
-        * @param string $body
-        * @return string
-        */
-       public static function limitBodySize($body)
+       private static function setHashtags(&$item)
        {
-               $maxlen = get_max_import_size();
-
-               // If the length of the body, including the embedded images, is smaller
-               // than the maximum, then don't waste time looking for the images
-               if ($maxlen && (strlen($body) > $maxlen)) {
-
-                       logger('the total body length exceeds the limit', LOGGER_DEBUG);
-
-                       $orig_body = $body;
-                       $new_body = '';
-                       $textlen = 0;
-
-                       $img_start = strpos($orig_body, '[img');
-                       $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
-                       $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
-                       while (($img_st_close !== false) && ($img_end !== false)) {
-
-                               $img_st_close++; // make it point to AFTER the closing bracket
-                               $img_end += $img_start;
-                               $img_end += strlen('[/img]');
-
-                               if (!strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
-                                       // This is an embedded image
-
-                                       if (($textlen + $img_start) > $maxlen) {
-                                               if ($textlen < $maxlen) {
-                                                       logger('the limit happens before an embedded image', LOGGER_DEBUG);
-                                                       $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
-                                                       $textlen = $maxlen;
-                                               }
-                                       } else {
-                                               $new_body = $new_body . substr($orig_body, 0, $img_start);
-                                               $textlen += $img_start;
-                                       }
-
-                                       $new_body = $new_body . substr($orig_body, $img_start, $img_end - $img_start);
-                               } else {
-
-                                       if (($textlen + $img_end) > $maxlen) {
-                                               if ($textlen < $maxlen) {
-                                                       logger('the limit happens before the end of a non-embedded image', LOGGER_DEBUG);
-                                                       $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
-                                                       $textlen = $maxlen;
-                                               }
-                                       } else {
-                                               $new_body = $new_body . substr($orig_body, 0, $img_end);
-                                               $textlen += $img_end;
-                                       }
-                               }
-                               $orig_body = substr($orig_body, $img_end);
-
-                               if ($orig_body === false) {
-                                       // in case the body ends on a closing image tag
-                                       $orig_body = '';
-                               }
-
-                               $img_start = strpos($orig_body, '[img');
-                               $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
-                               $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
-                       }
-
-                       if (($textlen + strlen($orig_body)) > $maxlen) {
-                               if ($textlen < $maxlen) {
-                                       logger('the limit happens after the end of the last image', LOGGER_DEBUG);
-                                       $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
-                               }
-                       } else {
-                               logger('the text size with embedded images extracted did not violate the limit', LOGGER_DEBUG);
-                               $new_body = $new_body . $orig_body;
-                       }
-
-                       return $new_body;
-               } else {
-                       return $body;
-               }
-       }
-
-       private static function setHashtags(&$item) {
 
                $tags = get_tags($item["body"]);
 
@@ -1222,7 +1141,8 @@ class Item
                $item["body"] = str_replace("&num;", "#", $item["body"]);
        }
 
-       public static function getGuidById($id) {
+       public static function getGuidById($id)
+       {
                $r = q("SELECT `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($id));
                if (DBM::is_result($r)) {
                        return $r[0]["guid"];
@@ -1231,8 +1151,8 @@ class Item
                }
        }
 
-       public static function getIdAndNickByGuid($guid, $uid = 0) {
-
+       public static function getIdAndNickByGuid($guid, $uid = 0)
+       {
                $nick = "";
                $id = 0;
 
@@ -1377,7 +1297,8 @@ class Item
 
        }
 
-       public static function isRemoteSelf($contact, &$datarray) {
+       public static function isRemoteSelf($contact, &$datarray)
+       {
                $a = get_app();
 
                if (!$contact['remote_self']) {
@@ -1564,7 +1485,8 @@ class Item
                return $new_body;
        }
 
-       private static function hasPermissions($obj) {
+       private static function hasPermissions($obj)
+       {
                return (
                        (
                                x($obj, 'allow_cid')
@@ -1578,7 +1500,8 @@ class Item
                );
        }
 
-       private static function samePermissions($obj1, $obj2) {
+       private static function samePermissions($obj1, $obj2)
+       {
                // first part is easy. Check that these are exactly the same.
                if (($obj1['allow_cid'] == $obj2['allow_cid'])
                        && ($obj1['allow_gid'] == $obj2['allow_gid'])
@@ -1598,7 +1521,8 @@ class Item
        }
 
        // returns an array of contact-ids that are allowed to see this object
-       private static function enumeratePermissions($obj) {
+       private static function enumeratePermissions($obj)
+       {
                $allow_people = expand_acl($obj['allow_cid']);
                $allow_groups = Group::expand(expand_acl($obj['allow_gid']));
                $deny_people  = expand_acl($obj['deny_cid']);
@@ -1609,7 +1533,8 @@ class Item
                return $recipients;
        }
 
-       public static function getFeedTags($item) {
+       public static function getFeedTags($item)
+       {
                $ret = [];
                $matches = false;
                $cnt = preg_match_all('|\#\[url\=(.*?)\](.*?)\[\/url\]|', $item['tag'], $matches);
@@ -1632,8 +1557,8 @@ class Item
                return $ret;
        }
 
-       public static function expire($uid, $days, $network = "", $force = false) {
-
+       public static function expire($uid, $days, $network = "", $force = false)
+       {
                if (!$uid || ($days < 1)) {
                        return;
                }
@@ -1709,7 +1634,8 @@ class Item
        }
 
        /// @TODO: This query seems to be really slow
-       public static function firstPostDate($uid, $wall = false) {
+       public static function firstPostDate($uid, $wall = false)
+       {
                $r = q("SELECT `id`, `created` FROM `item`
                        WHERE `uid` = %d AND `wall` = %d AND `deleted` = 0 AND `visible` = 1 AND `moderated` = 0
                        AND `id` = `parent`
@@ -1718,8 +1644,234 @@ class Item
                        intval($wall ? 1 : 0)
                );
                if (DBM::is_result($r)) {
-                       return substr(datetime_convert('',date_default_timezone_get(), $r[0]['created']),0,10);
+                       return substr(Temporal::convert($r[0]['created'], date_default_timezone_get()),0,10);
                }
                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('<link rel="alternate" type="text/html" href="' . System::baseUrl() . '/display/' . $owner_self_contact['nick'] . '/' . $item['id'] . '" />' . "\n") ;
+               $body = $item['body'];
+
+               $obj = <<< EOT
+
+               <object>
+                       <type>$objtype</type>
+                       <local>1</local>
+                       <id>{$item['uri']}</id>
+                       <link>$link</link>
+                       <title></title>
+                       <content>$body</content>
+               </object>
+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;
+       }
 }