diff --git a/include/api.php b/include/api.php
index e50bc92a8..1e8ba13d4 100644
--- a/include/api.php
+++ b/include/api.php
@@ -2218,7 +2218,7 @@ function api_statuses_destroy($type)
$ret = api_statuses_show($type);
- Item::delete($id);
+ Item::deleteById($id);
return $ret;
}
@@ -2459,9 +2459,7 @@ function api_favorites_create_destroy($type)
throw new BadRequestException("Invalid action ".$action);
}
- $r = q("UPDATE item SET starred=%d WHERE id=%d AND uid=%d", $item[0]['starred'], $itemid, api_user());
-
- q("UPDATE thread SET starred=%d WHERE iid=%d AND uid=%d", $item[0]['starred'], $itemid, api_user());
+ Item::update(['starred' => $item[0]['starred']], ['id' => $itemid]);
if ($r === false) {
throw new InternalServerErrorException("DB error");
@@ -3991,7 +3989,7 @@ function api_fr_photoalbum_delete($type)
if (!DBM::is_result($photo_item)) {
throw new InternalServerErrorException("problem with deleting items occured");
}
- Item::delete($photo_item[0]['id']);
+ Item::deleteById($photo_item[0]['id']);
}
// now let's delete all photos from the album
@@ -4294,7 +4292,7 @@ function api_fr_photo_delete($type)
}
// function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore
// to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion)
- Item::delete($photo_item[0]['id']);
+ Item::deleteById($photo_item[0]['id']);
$answer = ['result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.'];
return api_format_data("photo_delete", $type, ['$result' => $answer]);
diff --git a/include/event.php b/include/event.php
index 30ba1cfde..cce2a98cc 100644
--- a/include/event.php
+++ b/include/event.php
@@ -318,13 +318,8 @@ function event_store($arr) {
$object .= '
"; var_dump($i); killme(); + if (DBM::is_result($i)) { - q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(DateTimeFormat::utcNow()), - dbesc(DateTimeFormat::utcNow()), - dbesc($i[0]['uri']), - intval(local_user()) - ); - Term::insertFromTagFieldByItemUri($i[0]['uri'], local_user()); - Item::deleteThreadByUri($i[0]['uri'], local_user()); - - $url = System::baseUrl(); - $drop_id = intval($i[0]['id']); - - if ($i[0]['visible']) { - Worker::add(PRIORITY_HIGH, "Notifier", "drop", $drop_id); - } + Item::deleteById($i[0]['id']); } } diff --git a/src/Model/Item.php b/src/Model/Item.php index 01edf8d95..88efb6aa6 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -29,6 +29,7 @@ use Text_LanguageDetect; require_once 'boot.php'; require_once 'include/items.php'; require_once 'include/text.php'; +require_once 'include/event.php'; class Item extends BaseObject { @@ -78,17 +79,35 @@ class Item extends BaseObject return $rows; } + /** + * @brief Delete an item and notify others about it - if it was ours + * + * @param array $condition The condition for finding the item entries + * @param integer $priority Priority for the notification + */ + public static function delete($condition, $priority = PRIORITY_HIGH) + { + $items = dba::select('item', ['id'], $condition); + while ($item = dba::fetch($items)) { + self::deleteById($item['id'], $priority); + } + dba::close($items); + } + /** * @brief Delete an item and notify others about it - if it was ours * * @param integer $item_id Item ID that should be delete + * @param integer $priority Priority for the notification * * @return $boolean success */ - public static function delete($item_id, $priority = PRIORITY_HIGH) + public static function deleteById($item_id, $priority = PRIORITY_HIGH) { // locate item to be deleted - $fields = ['id', 'uid', 'parent', 'parent-uri', 'origin', 'deleted', 'file', 'resource-id', 'event-id', 'attach']; + $fields = ['id', 'uid', 'parent', 'parent-uri', 'origin', 'deleted', + 'file', 'resource-id', 'event-id', 'attach', + 'verb', 'object-type', 'object', 'target', 'contact-id']; $item = dba::selectFirst('item', $fields, ['id' => $item_id]); if (!DBM::is_result($item)) { return false; @@ -134,9 +153,9 @@ class Item extends BaseObject dba::delete('photo', ['resource-id' => $item['resource-id'], 'uid' => $item['uid']]); } - // If item is a link to an event, nuke the event record. + // If item is a link to an event, delete the event. if (intval($item['event-id'])) { - dba::delete('event', ['id' => $item['event-id'], 'uid' => $item['uid']]); + event_delete($item['event-id']); } // If item has attachments, drop them @@ -145,6 +164,9 @@ class Item extends BaseObject dba::delete('attach', ['id' => $matches[1], 'uid' => $item['uid']]); } + // Delete tags that had been attached to other items + self::deleteTagsFromItem($item); + // Set the item to "deleted" dba::update('item', ['deleted' => true, 'title' => '', 'body' => '', 'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()], @@ -156,10 +178,7 @@ class Item extends BaseObject // If it's the parent of a comment thread, kill all the kids if ($item['id'] == $item['parent']) { - $items = dba::select('item', ['id'], ['parent' => $item['parent']]); - while ($row = dba::fetch($items)) { - self::delete($row['id'], $priority); - } + self::delete(['parent' => $item['parent']]); } // send the notification upstream/downstream @@ -170,6 +189,44 @@ class Item extends BaseObject return true; } + private static function deleteTagsFromItem($item) + { + if (($item["verb"] != ACTIVITY_TAG) || ($item["object-type"] != ACTIVITY_OBJ_TAGTERM)) { + return; + } + + $xo = XML::parseString($item["object"], false); + $xt = XML::parseString($item["target"], false); + + if ($xt->type != ACTIVITY_OBJ_NOTE) { + return; + } + + $i = dba::selectFirst('item', ['id', 'contact-id', 'tag'], ['uri' => $xt->id, 'uid' => $item['uid']]); + if (!DBM::is_result($i)) { + return; + } + + // For tags, the owner cannot remove the tag on the author's copy of the post. + $owner_remove = ($item["contact-id"] == $i["contact-id"]); + $author_copy = $item["origin"]; + + if (($owner_remove && $author_copy) || !$owner_remove) { + return; + } + + $tags = explode(',', $i["tag"]); + $newtags = []; + if (count($tags)) { + foreach ($tags as $tag) { + if (trim($tag) !== trim($xo->body)) { + $newtags[] = trim($tag); + } + } + } + self::update(['tag' => implode(',', $newtags)], ['id' => $i["id"]]); + } + public static function insert($arr, $force_parent = false, $notify = false, $dontcache = false) { $a = get_app(); @@ -1626,7 +1683,7 @@ class Item extends BaseObject continue; } - self::delete($item['id'], PRIORITY_LOW); + self::deleteByID($item['id'], PRIORITY_LOW); } } @@ -1851,13 +1908,11 @@ EOT; 'unseen' => 1, ]; - $new_item_id = Item::insert($new_item); + $new_item_id = self::insert($new_item); - // @todo: Explain this block - if (! $item['visible']) { - q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", - intval($item['id']) - ); + // If the parent item isn't visible then set it to visible + if (!$item['visible']) { + self::update(['visible' => true], ['id' => $item['id']]); } // Save the author information for the like in case we need to relay to Diaspora @@ -1878,69 +1933,58 @@ EOT; `moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`, `gcontact-id`, `deleted`, `origin`, `forum_mode`, `mention`, `network`, `author-id`, `owner-id` FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid)); - + if (!$items) { return; } - + $item = $items[0]; $item['iid'] = $itemid; - + if (!$onlyshadow) { $result = dba::insert('thread', $item); - + logger("Add thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG); } } - public static function updateThreadByUri($itemuri, $uid) - { - $messages = dba::select('item', ['id'], ['uri' => $itemuri, 'uid' => $uid]); - - if (DBM::is_result($messages)) { - foreach ($messages as $message) { - self::updateThread($message["id"]); - } - } - } - - public static function updateThread($itemid, $setmention = false) + private static function updateThread($itemid, $setmention = false) { $items = q("SELECT `uid`, `guid`, `title`, `body`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`, `moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`, `gcontact-id`, `deleted`, `origin`, `forum_mode`, `network`, `rendered-html`, `rendered-hash` FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid)); - + if (!DBM::is_result($items)) { return; } - + $item = $items[0]; - + if ($setmention) { $item["mention"] = 1; } - + $sql = ""; - + foreach ($item as $field => $data) if (!in_array($field, ["guid", "title", "body", "rendered-html", "rendered-hash"])) { if ($sql != "") { $sql .= ", "; } - + $sql .= "`".$field."` = '".dbesc($data)."'"; } - + $result = q("UPDATE `thread` SET ".$sql." WHERE `iid` = %d", intval($itemid)); - + logger("Update thread for item ".$itemid." - guid ".$item["guid"]." - ".print_r($result, true)." ".print_r($item, true), LOGGER_DEBUG); - + // Updating a shadow item entry $items = dba::selectFirst('item', ['id'], ['guid' => $item['guid'], 'uid' => 0]); - + if (!DBM::is_result($items)) { return; } - + $result = dba::update( 'item', ['title' => $item['title'], 'body' => $item['body'], 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']], @@ -1949,31 +1993,20 @@ EOT; logger("Updating public shadow for post ".$items["id"]." - guid ".$item["guid"]." Result: ".print_r($result, true), LOGGER_DEBUG); } - - public static function deleteThreadByUri($itemuri, $uid) - { - $messages = dba::select('item', ['id'], ['uri' => $itemuri, 'uid' => $uid]); - - if (DBM::is_result($messages)) { - foreach ($messages as $message) { - self::deleteThread($message["id"], $itemuri); - } - } - } - - public static function deleteThread($itemid, $itemuri = "") + + private static function deleteThread($itemid, $itemuri = "") { $item = dba::selectFirst('thread', ['uid'], ['iid' => $itemid]); if (!DBM::is_result($item)) { logger('No thread found for id '.$itemid, LOGGER_DEBUG); return; } - + // Using dba::delete at this time could delete the associated item entries $result = dba::e("DELETE FROM `thread` WHERE `iid` = ?", $itemid); - + logger("deleteThread: Deleted thread for item ".$itemid." - ".print_r($result, true), LOGGER_DEBUG); - + if ($itemuri != "") { $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND NOT `deleted` AND NOT (`uid` IN (%d, 0))", dbesc($itemuri), diff --git a/src/Model/Term.php b/src/Model/Term.php index c730bf744..d950d1d5f 100644 --- a/src/Model/Term.php +++ b/src/Model/Term.php @@ -122,19 +122,6 @@ class Term } } - public static function insertFromTagFieldByItemUri($itemuri, $uid) - { - $messages = dba::select('item', ['id'], ['uri' => $itemuri, 'uid' => $uid]); - - if (DBM::is_result($messages)) { - while ($message = dba::fetch($messages)) { - self::insertFromTagFieldByItemId($message['id']); - } - dba::close($messages); - } - } - - /** * @param integer $itemid item id * @return void @@ -181,20 +168,4 @@ class Term } } } - - /** - * @param string $itemuri item uri - * @param integer $uid uid - * @return void - */ - public static function insertFromFileFieldByItemUri($itemuri, $uid) - { - $messages = q("SELECT `id` FROM `item` WHERE uri ='%s' AND uid=%d", dbesc($itemuri), intval($uid)); - - if (count($messages)) { - foreach ($messages as $message) { - self::insertFromFileFieldByItemId($message["id"]); - } - } - } } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 2b3b9b0dc..6ec83151f 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -2088,10 +2088,7 @@ class DFRN 'edited' => DateTimeFormat::utc($item["edited"])]; $condition = ["`uri` = ? AND `uid` IN (0, ?)", $item["uri"], $importer["importer_uid"]]; - dba::update('item', $fields, $condition); - - Term::insertFromTagFieldByItemUri($item["uri"], $importer["importer_uid"]); - Item::updateThreadByUri($item["uri"], $importer["importer_uid"]); + Item::update($fields, $condition); $changed = true; @@ -2328,13 +2325,9 @@ class DFRN // extract tag, if not duplicate, add to parent item if ($xo->content) { - if (!(stristr($r[0]["tag"], trim($xo->content)))) { - q( - "UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), - intval($r[0]["id"]) - ); - Term::insertFromTagFieldByItemId($r[0]["id"]); + if (!stristr($r[0]["tag"], trim($xo->content))) { + $tag = $r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; + Item::update(['tag' => $tag], ['id' => $r[0]["id"]]); } } } @@ -2746,121 +2739,35 @@ class DFRN if ($attributes->name == "ref") { $uri = $attributes->textContent; } - if ($attributes->name == "when") { - $when = $attributes->textContent; - } - } - if ($when) { - $when = DateTimeFormat::utc($when); - } else { - $when = DateTimeFormat::utcNow(); } if (!$uri || !$importer["id"]) { return false; } - /// @todo Only select the used fields - $r = q( - "SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` - WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", - dbesc($uri), - intval($importer["uid"]), - intval($importer["id"]) - ); - if (!DBM::is_result($r)) { + $condition = ["`uri` = ? AND `uid` = ? AND `contact-id` = ? AND NOT `file` LIKE '%[%'", + $uri, $importer["uid"], $importer["id"]]; + $item = dba::selectFirst('item', ['id'], $condition); + if (!DBM::is_result($item)) { logger("Item with uri " . $uri . " from contact " . $importer["id"] . " for user " . $importer["uid"] . " wasn't found.", LOGGER_DEBUG); return; + } + + $entrytype = self::getEntryType($importer, $item); + + if (!$item["deleted"]) { + logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); } else { - $item = $r[0]; + return; + } - $entrytype = self::getEntryType($importer, $item); + Item::deleteById($item["id"]); - if (!$item["deleted"]) { - logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); - } else { - return; - } - - if ($item["object-type"] == ACTIVITY_OBJ_EVENT) { - logger("Deleting event ".$item["event-id"], LOGGER_DEBUG); - event_delete($item["event-id"]); - } - - if (($item["verb"] == ACTIVITY_TAG) && ($item["object-type"] == ACTIVITY_OBJ_TAGTERM)) { - $xo = XML::parseString($item["object"], false); - $xt = XML::parseString($item["target"], false); - - if ($xt->type == ACTIVITY_OBJ_NOTE) { - $i = q( - "SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($xt->id), - intval($importer["importer_uid"]) - ); - if (DBM::is_result($i)) { - // For tags, the owner cannot remove the tag on the author's copy of the post. - - $owner_remove = (($item["contact-id"] == $i[0]["contact-id"]) ? true: false); - $author_remove = (($item["origin"] && $item["self"]) ? true : false); - $author_copy = (($item["origin"]) ? true : false); - - if ($owner_remove && $author_copy) { - return; - } - if ($author_remove || $owner_remove) { - $tags = explode(',', $i[0]["tag"]); - $newtags = []; - if (count($tags)) { - foreach ($tags as $tag) { - if (trim($tag) !== trim($xo->body)) { - $newtags[] = trim($tag); - } - } - } - q( - "UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc(implode(',', $newtags)), - intval($i[0]["id"]) - ); - Term::insertFromTagFieldByItemId($i[0]["id"]); - } - } - } - } - - if ($entrytype == DFRN_TOP_LEVEL) { - $r = q( - "UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `parent-uri` = '%s' AND `uid` IN (0, %d)", - dbesc($when), - dbesc(DateTimeFormat::utcNow()), - dbesc($uri), - intval($importer["uid"]) - ); - Term::insertFromTagFieldByItemUri($uri, $importer["uid"]); - Term::insertFromFileFieldByItemUri($uri, $importer["uid"]); - Item::updateThreadByUri($uri, $importer["uid"]); - } else { - $r = q( - "UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `uri` = '%s' AND `uid` IN (0, %d)", - dbesc($when), - dbesc(DateTimeFormat::utcNow()), - dbesc($uri), - intval($importer["uid"]) - ); - Term::insertFromTagFieldByItemUri($uri, $importer["uid"]); - Term::insertFromFileFieldByItemUri($uri, $importer["uid"]); - Item::updateThreadByUri($uri, $importer["importer_uid"]); - - // if this is a relayed delete, propagate it to other recipients - - if ($entrytype == DFRN_REPLY_RC) { - logger("Notifying followers about deletion of post " . $item["id"], LOGGER_DEBUG); - Worker::add(PRIORITY_HIGH, "Notifier", "drop", $item["id"]); - } + if ($entrytype != DFRN_TOP_LEVEL) { + // if this is a relayed delete, propagate it to other recipients + if ($entrytype == DFRN_REPLY_RC) { + logger("Notifying followers about deletion of post " . $item["id"], LOGGER_DEBUG); + Worker::add(PRIORITY_HIGH, "Notifier", "drop", $item["id"]); } } } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 2b5905c95..0f5c9c0c9 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -2842,23 +2842,7 @@ class Diaspora continue; } - // Currently we don't have a central deletion function that we could use in this case. - // The function "item_drop" doesn't work for that case - dba::update( - 'item', - [ - 'deleted' => true, - 'title' => '', - 'body' => '', - 'edited' => DateTimeFormat::utcNow(), - 'changed' => DateTimeFormat::utcNow()], - ['id' => $item["id"]] - ); - - // Delete the thread - if it is a starting post and not a comment - if ($target_type != 'Comment') { - Item::deleteThread($item["id"], $item["parent-uri"]); - } + Item::deleteById($item["id"]); logger("Deleted target ".$target_guid." (".$item["id"].") from user ".$item["uid"]." parent: ".$item["parent"], LOGGER_DEBUG); diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 8688b5a7f..1ff13c55d 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -552,16 +552,7 @@ class OStatus return; } - // Currently we don't have a central deletion function that we could use in this case - // The function "item_drop" doesn't work for that case - dba::update( - 'item', - ['deleted' => true, 'title' => '', 'body' => '', - 'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()], - ['id' => $deleted["id"]] - ); - - Item::deleteThread($deleted["id"], $deleted["parent-uri"]); + Item::deleteById($deleted["id"]); logger('Deleted item with uri '.$item['uri'].' for user '.$item['uid']); } diff --git a/src/Worker/OnePoll.php b/src/Worker/OnePoll.php index 42c2774fa..377bda85f 100644 --- a/src/Worker/OnePoll.php +++ b/src/Worker/OnePoll.php @@ -395,7 +395,7 @@ class OnePoll if (($mailconf['action'] != 1) && ($mailconf['action'] != 3)) if ($meta->deleted && ! $item['deleted']) { $fields = ['deleted' => true, 'changed' => DateTimeFormat::utcNow()]; - dba::update('item', $fields, ['id' => $item['id']]); + Item::update($fields, ['id' => $item['id']]); } switch ($mailconf['action']) {