We now store the verb in the item-content as well
authorMichael <heluecht@pirati.ca>
Wed, 27 Jun 2018 19:37:13 +0000 (19:37 +0000)
committerMichael <heluecht@pirati.ca>
Wed, 27 Jun 2018 19:37:13 +0000 (19:37 +0000)
boot.php
include/api.php
src/Database/DBStructure.php
src/Model/Item.php
src/Protocol/DFRN.php
src/Protocol/OStatus.php

index 64abddd..864e780 100644 (file)
--- a/boot.php
+++ b/boot.php
@@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM',     'Friendica');
 define('FRIENDICA_CODENAME',     'The Tazmans Flax-lily');
 define('FRIENDICA_VERSION',      '2018.08-dev');
 define('DFRN_PROTOCOL_VERSION',  '2.23');
-define('DB_UPDATE_VERSION',      1271);
+define('DB_UPDATE_VERSION',      1272);
 define('NEW_UPDATE_ROUTINE_VERSION', 1170);
 
 /**
index 2eaabd8..32fe6c6 100644 (file)
@@ -1626,7 +1626,7 @@ function api_statuses_home_timeline($type)
        }
 
        if (!empty($idarray)) {
-               $unseen = dba::exists('item', ['unseen' => true, 'id' => $idarray]);
+               $unseen = Item::exists(['unseen' => true, 'id' => $idarray]);
                if ($unseen) {
                        Item::update(['unseen' => false], ['unseen' => true, 'id' => $idarray]);
                }
index eaf54ce..8fb2afd 100644 (file)
@@ -1270,6 +1270,7 @@ class DBStructure
                                                "target-type" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams target type if applicable (URI)"],
                                                "target" => ["type" => "text", "comment" => "JSON encoded target structure if used"],
                                                "plink" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "permalink or URL to a displayable copy of the message at its source"],
+                                               "verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams verb"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
index fe6dc5d..2dac079 100644 (file)
@@ -58,7 +58,7 @@ class Item extends BaseObject
 
        // Field list for "item-content" table that is mixed with the item table
        const CONTENT_FIELDLIST = ['title', 'content-warning', 'body', 'location',
-                       'coord', 'app', 'rendered-hash', 'rendered-html',
+                       'coord', 'app', 'rendered-hash', 'rendered-html', 'verb',
                        'object-type', 'object', 'target-type', 'target'];
 
        // All fields in the item table
@@ -143,6 +143,27 @@ class Item extends BaseObject
                return $data;
        }
 
+       /**
+        * @brief Check if item data exists
+        *
+        * @param array $condition array of fields for condition
+        *
+        * @return boolean Are there rows for that condition?
+        */
+       public static function exists($condition) {
+               $stmt = self::select(['id'], $condition, ['limit' => 1]);
+
+               if (is_bool($stmt)) {
+                       $retval = $stmt;
+               } else {
+                       $retval = (dba::num_rows($stmt) > 0);
+               }
+
+               dba::close($stmt);
+
+               return $retval;
+       }
+
        /**
         * Retrieve a single record from the item table for a given user and returns it in an associative array
         *
@@ -377,8 +398,8 @@ class Item extends BaseObject
 
                $fields['item'] = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', 'guid',
                        'contact-id', 'owner-id', 'author-id', 'type', 'wall', 'gravity', 'extid',
-                       'created', 'edited', 'commented', 'received', 'changed', 'verb',
-                       'postopts', 'plink', 'resource-id', 'event-id', 'tag', 'attach', 'inform',
+                       'created', 'edited', 'commented', 'received', 'changed', 'postopts',
+                       'plink', 'resource-id', 'event-id', 'tag', 'attach', 'inform',
                        'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
                        'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark',
                        'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global',
@@ -728,15 +749,14 @@ class Item extends BaseObject
                self::deleteTagsFromItem($item);
 
                // Set the item to "deleted"
-               dba::update('item', ['deleted' => true, 'title' => '', 'body' => '',
-                                       'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()],
+               dba::update('item', ['deleted' => true, 'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()],
                                ['id' => $item['id']]);
 
                Term::insertFromTagFieldByItemId($item['id']);
                Term::insertFromFileFieldByItemId($item['id']);
                self::deleteThread($item['id'], $item['parent-uri']);
 
-               if (!dba::exists('item', ["`uri` = ? AND `uid` != 0 AND NOT `deleted`", $item['uri']])) {
+               if (!self::exists(["`uri` = ? AND `uid` != 0 AND NOT `deleted`", $item['uri']])) {
                        self::delete(['uri' => $item['uri'], 'uid' => 0, 'deleted' => false], $priority);
                }
 
@@ -1120,7 +1140,7 @@ class Item extends BaseObject
                // Checking if there is already an item with the same guid
                logger('Checking for an item for user '.$item['uid'].' on network '.$item['network'].' with the guid '.$item['guid'], LOGGER_DEBUG);
                $condition = ['guid' => $item['guid'], 'network' => $item['network'], 'uid' => $item['uid']];
-               if (dba::exists('item', $condition)) {
+               if (self::exists($condition)) {
                        logger('found item with guid '.$item['guid'].' for user '.$item['uid'].' on network '.$item['network'], LOGGER_DEBUG);
                        return 0;
                }
@@ -1234,7 +1254,7 @@ class Item extends BaseObject
 
                $condition = ["`uri` = ? AND `network` IN (?, ?) AND `uid` = ?",
                        $item['uri'], $item['network'], NETWORK_DFRN, $item['uid']];
-               if (dba::exists('item', $condition)) {
+               if (self::exists($condition)) {
                        logger('duplicated item with the same uri found. '.print_r($item,true));
                        return 0;
                }
@@ -1242,7 +1262,7 @@ class Item extends BaseObject
                // On Friendica and Diaspora the GUID is unique
                if (in_array($item['network'], [NETWORK_DFRN, NETWORK_DIASPORA])) {
                        $condition = ['guid' => $item['guid'], 'uid' => $item['uid']];
-                       if (dba::exists('item', $condition)) {
+                       if (self::exists($condition)) {
                                logger('duplicated item with the same guid found. '.print_r($item,true));
                                return 0;
                        }
@@ -1250,7 +1270,7 @@ class Item extends BaseObject
                        // Check for an existing post with the same content. There seems to be a problem with OStatus.
                        $condition = ["`body` = ? AND `network` = ? AND `created` = ? AND `contact-id` = ? AND `uid` = ?",
                                        $item['body'], $item['network'], $item['created'], $item['contact-id'], $item['uid']];
-                       if (dba::exists('item', $condition)) {
+                       if (self::exists($condition)) {
                                logger('duplicated item with the same body found. '.print_r($item,true));
                                return 0;
                        }
@@ -1263,7 +1283,7 @@ class Item extends BaseObject
                        // Set the global flag on all items if this was a global item entry
                        dba::update('item', ['global' => true], ['uri' => $item["uri"]]);
                } else {
-                       $item["global"] = dba::exists('item', ['uid' => 0, 'uri' => $item["uri"]]);
+                       $item["global"] = self::exists(['uid' => 0, 'uri' => $item["uri"]]);
                }
 
                // ACL settings
@@ -1304,7 +1324,7 @@ class Item extends BaseObject
                 * An unique index would help - but the limitations of MySQL (maximum size of index values) prevent this.
                 */
                if ($item["uid"] == 0) {
-                       if (dba::exists('item', ['uri' => trim($item['uri']), 'uid' => 0])) {
+                       if (self::exists(['uri' => trim($item['uri']), 'uid' => 0])) {
                                logger('Global item already stored. URI: '.$item['uri'].' on network '.$item['network'], LOGGER_DEBUG);
                                return 0;
                        }
@@ -1671,7 +1691,7 @@ class Item extends BaseObject
                if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
                        ($item["deny_cid"] == '') && ($item["deny_gid"] == '')) {
 
-                       if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
+                       if (!self::exists(['uri' => $item['uri'], 'uid' => 0])) {
                                // Preparing public shadow (removing user specific data)
                                $item['uid'] = 0;
                                unset($item['id']);
@@ -1725,12 +1745,12 @@ class Item extends BaseObject
                }
 
                // Is there a shadow parent?
-               if (!dba::exists('item', ['uri' => $item['parent-uri'], 'uid' => 0])) {
+               if (!self::exists(['uri' => $item['parent-uri'], 'uid' => 0])) {
                        return;
                }
 
                // Is there already a shadow entry?
-               if (dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
+               if (self::exists(['uri' => $item['uri'], 'uid' => 0])) {
                        return;
                }
 
@@ -1760,7 +1780,7 @@ class Item extends BaseObject
 
                // If this was a comment to a Diaspora post we don't get our comment back.
                // This means that we have to distribute the comment by ourselves.
-               if ($origin && dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) {
+               if ($origin && self::exists(['id' => $parent, 'network' => NETWORK_DIASPORA])) {
                        self::distribute($public_shadow);
                }
        }
@@ -2570,30 +2590,32 @@ class Item extends BaseObject
                // 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) . "'";
+                       $verbs = [ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE];
                } else {
-                       $verbs = "'".dbesc($activity)."'";
-               }
-
-               /// @todo This query is expected to be a performance eater due to the "OR" - it has to be changed totally
-               $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'])
-               );
+                       $verbs = $activity;
+               }
 
-               // If it exists, mark it as deleted
-               if (DBM::is_result($existing_like)) {
-                       $like_item = $existing_like[0];
+               $base_condition = ['verb' => $verbs, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY,
+                       'author-id' => $author_contact['id'], 'uid' => item['uid']];
+
+               $condition = array_merge($base_condition, ['parent' => $item_id]);
+               $like_item = self::selectFirst(['id', 'guid', 'verb'], $condition);
 
+               if (!DBM::is_result($like_item)) {
+                       $condition = array_merge($base_condition, ['parent-uri' => $item_id]);
+                       $like_item = self::selectFirst(['id', 'guid', 'verb'], $condition);
+               }
+
+               if (!DBM::is_result($like_item)) {
+                       $condition = array_merge($base_condition, ['thr-parent' => $item_id]);
+                       $like_item = self::selectFirst(['id', 'guid', 'verb'], $condition);
+               }
+
+               // If it exists, mark it as deleted
+               if (DBM::is_result($like_item)) {
                        // Already voted, undo it
                        $fields = ['deleted' => true, 'unseen' => true, 'changed' => DateTimeFormat::utcNow()];
+                       /// @todo Consider using self::update - but before doing so, check the side effects
                        dba::update('item', $fields, ['id' => $like_item['id']]);
 
                        // Clean up the Diaspora signatures for this like
@@ -2757,7 +2779,7 @@ EOT;
 
                if ($itemuri != "") {
                        $condition = ["`uri` = ? AND NOT `deleted` AND NOT (`uid` IN (?, 0))", $itemuri, $item["uid"]];
-                       if (!dba::exists('item', $condition)) {
+                       if (!self::exists($condition)) {
                                dba::delete('item', ['uri' => $itemuri, 'uid' => 0]);
                                logger("deleteThread: Deleted shadow for item ".$itemuri, LOGGER_DEBUG);
                        }
index 0b8cb73..c1e116f 100644 (file)
@@ -2313,15 +2313,15 @@ class DFRN
                                $item["gravity"] = GRAVITY_ACTIVITY;
                                // only one like or dislike per person
                                // splitted into two queries for performance issues
-                               $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"],
+                               $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY,
                                        'verb' => $item["verb"], 'parent-uri' => $item["parent-uri"]];
-                               if (dba::exists('item', $condition)) {
+                               if (Item::exists($condition)) {
                                        return false;
                                }
 
-                               $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"],
+                               $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY,
                                        'verb' => $item["verb"], 'thr-parent' => $item["parent-uri"]];
-                               if (dba::exists('item', $condition)) {
+                               if (Item::exists($condition)) {
                                        return false;
                                }
                        } else {
@@ -2770,7 +2770,7 @@ class DFRN
                // Comments can be deleted by the thread owner or comment owner
                if (($item['id'] != $item['parent']) && ($item['contact-id'] != $importer["id"])) {
                        $condition = ['id' => $item['parent'], 'contact-id' => $importer["id"]];
-                       if (!dba::exists('item', $condition)) {
+                       if (!Item::exists($condition)) {
                                logger("Item with uri " . $uri . " wasn't found or mustn't be deleted by contact " . $importer["id"] . " - ignoring deletion.", LOGGER_DEBUG);
                                return;
                        }
index 9aef084..4538d36 100644 (file)
@@ -416,7 +416,7 @@ class OStatus
                        }
 
                        // Deletions come with the same uri, so we check for duplicates after processing deletions
-                       if (dba::exists('item', ['uid' => $importer["uid"], 'uri' => $item["uri"]])) {
+                       if (Item::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]])) {
                                logger('Post with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.', LOGGER_DEBUG);
                                continue;
                        } else {
@@ -489,7 +489,7 @@ class OStatus
                                        }
                                } else {
                                        // But we will only import complete threads
-                                       $valid = dba::exists('item', ['uid' => $importer["uid"], 'uri' => self::$itemlist[0]['parent-uri']]);
+                                       $valid = Item::exists(['uid' => $importer["uid"], 'uri' => self::$itemlist[0]['parent-uri']]);
                                        if ($valid) {
                                                logger("Item with uri ".self::$itemlist[0]["uri"]." belongs to parent ".self::$itemlist[0]['parent-uri']." of user ".$importer["uid"].". It will be imported.", LOGGER_DEBUG);
                                        }
@@ -506,7 +506,7 @@ class OStatus
                                                }
                                        }
                                        foreach (self::$itemlist as $item) {
-                                               $found = dba::exists('item', ['uid' => $importer["uid"], 'uri' => $item["uri"]]);
+                                               $found = Item::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]]);
                                                if ($found) {
                                                        logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already exists.", LOGGER_DEBUG);
                                                } elseif ($item['contact-id'] < 0) {
@@ -537,8 +537,8 @@ class OStatus
         */
        private static function deleteNotice($item)
        {
-               $condition = ['uid' => $item['uid'], 'author-link' => $item['author-link'], 'uri' => $item['uri']];
-               if (!dba::exists('item', $condition)) {
+               $condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'uri' => $item['uri']];
+               if (!Item::exists($condition)) {
                        logger('Item from '.$item['author-link'].' with uri '.$item['uri'].' for user '.$item['uid']." wasn't found. We don't delete it.");
                        return;
                }
@@ -674,7 +674,7 @@ class OStatus
                }
 
                if (isset($item["parent-uri"])) {
-                       if (!dba::exists('item', ['uid' => $importer["uid"], 'uri' => $item['parent-uri']])) {
+                       if (!Item::exists(['uid' => $importer["uid"], 'uri' => $item['parent-uri']])) {
                                if ($related != '') {
                                        self::fetchRelated($related, $item["parent-uri"], $importer);
                                }