diff --git a/boot.php b/boot.php index 78bd68f3e4..66e44677b7 100644 --- 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.05-rc'); define('DFRN_PROTOCOL_VERSION', '2.23'); -define('DB_UPDATE_VERSION', 1265); +define('DB_UPDATE_VERSION', 1266); define('NEW_UPDATE_ROUTINE_VERSION', 1170); /** diff --git a/database.sql b/database.sql index 64ac656fd9..7c0a593795 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2018.05-rc (The Tazmans Flax-lily) --- DB_UPDATE_VERSION 1265 +-- DB_UPDATE_VERSION 1266 -- ------------------------------------------ @@ -1076,6 +1076,16 @@ CREATE TABLE IF NOT EXISTS `userd` ( INDEX `username` (`username`(32)) ) DEFAULT COLLATE utf8mb4_general_ci; +-- +-- TABLE user-item +-- +CREATE TABLE IF NOT EXISTS `user-item` ( + `iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item id', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', + `hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Hidden marker', + PRIMARY KEY(`uid`,`iid`) +) DEFAULT COLLATE utf8mb4_general_ci; + -- -- TABLE workerqueue -- diff --git a/include/api.php b/include/api.php index 628b86c649..e25d12c40a 100644 --- a/include/api.php +++ b/include/api.php @@ -1663,7 +1663,7 @@ function api_search($type) $r = dba::p( "SELECT ".item_fieldlists()." - FROM `item` ".item_joins()." + FROM `item` ".item_joins(api_user())." WHERE ".item_condition()." AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) AND `item`.`body` LIKE CONCAT('%',?,'%') $sql_extra @@ -1827,7 +1827,7 @@ function api_statuses_public_timeline($type) "SELECT " . item_fieldlists() . " FROM `thread` STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " + " . item_joins(api_user()) . " STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall` AND `verb` = ? @@ -1856,7 +1856,7 @@ function api_statuses_public_timeline($type) $r = dba::p( "SELECT " . item_fieldlists() . " FROM `item` - " . item_joins() . " + " . item_joins(api_user()) . " STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid` AND NOT `user`.`hidewall` AND `verb` = ? @@ -1930,7 +1930,7 @@ function api_statuses_networkpublic_timeline($type) "SELECT " . item_fieldlists() . " FROM `thread` STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " + " . item_joins(api_user()) . " WHERE `thread`.`uid` = 0 AND `verb` = ? AND NOT `thread`.`private` diff --git a/include/conversation.php b/include/conversation.php index 324b53b5a8..fb485baf12 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -405,10 +405,12 @@ function visible_activity($item) { /** * @brief SQL query for items + * + * @param int $uid user id */ -function item_query() { +function item_query($uid = 0) { return "SELECT " . item_fieldlists() . " FROM `item` " . - item_joins() . " WHERE " . item_condition(); + item_joins($uid) . " WHERE " . item_condition(); } /** @@ -467,16 +469,19 @@ These Fields are not added below (yet). They are here to for bug search. /** * @brief SQL join for contacts that are needed for displaying items + * + * @param int $uid user id */ -function item_joins() { +function item_joins($uid = 0) { return sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND NOT `contact`.`blocked` AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s))) OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0) INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked` INNER JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked` + LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d LEFT JOIN `event` ON `event-id` = `event`.`id`", - CONTACT_IS_SHARING, CONTACT_IS_FRIEND + CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid) ); } @@ -484,7 +489,7 @@ function item_joins() { * @brief SQL condition for items that are needed for displaying items */ function item_condition() { - return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`"; + return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) "; } /** @@ -497,7 +502,7 @@ function item_condition() { * that are based on unique features of the calling module. * */ -function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented') { +function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0) { require_once 'mod/proxy.php'; $ssl_state = ((local_user()) ? true : false); @@ -521,7 +526,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = $previewing = (($preview) ? ' preview ' : ''); if ($mode === 'network') { - $items = conversation_add_children($items, false, $order); + $items = conversation_add_children($items, false, $order, $uid); $profile_owner = local_user(); if (!$update) { /* @@ -885,7 +890,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = * * @return array items with parents and comments */ -function conversation_add_children($parents, $block_authors, $order) { +function conversation_add_children($parents, $block_authors, $order, $uid = 0) { $max_comments = Config::get('system', 'max_comments', 100); if ($max_comments > 0) { @@ -899,7 +904,7 @@ function conversation_add_children($parents, $block_authors, $order) { $block_sql = $block_authors ? "AND NOT `author`.`hidden` AND NOT `author`.`blocked`" : ""; foreach ($parents AS $parent) { - $thread_items = dba::p(item_query()."AND `item`.`parent-uri` = ? + $thread_items = dba::p(item_query(local_user())."AND `item`.`parent-uri` = ? AND `item`.`uid` IN (0, ?) $block_sql ORDER BY `item`.`uid` ASC, `item`.`commented` DESC" . $limit, $parent['uri'], local_user()); diff --git a/mod/display.php b/mod/display.php index ef5704c736..80e913d204 100644 --- a/mod/display.php +++ b/mod/display.php @@ -346,7 +346,7 @@ function display_content(App $a, $update = false, $update_uid = 0) { return ''; } - $r = dba::p(item_query()."AND `item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?) + $r = dba::p(item_query(local_user())."AND `item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?) AND `item`.`uid` IN (0, ?) $sql_extra ORDER BY `item`.`uid` ASC, `parent` DESC, `gravity` ASC, `id` ASC", $item_id, local_user() diff --git a/mod/network.php b/mod/network.php index 87594a77c4..2e7ae12e0b 100644 --- a/mod/network.php +++ b/mod/network.php @@ -345,7 +345,7 @@ function networkConversation($a, $items, $mode, $update, $ordering = '') // Set this so that the conversation function can find out contact info for our wall-wall items $a->page_contact = $a->contact; - $o = conversation($a, $items, $mode, $update, false, $ordering); + $o = conversation($a, $items, $mode, $update, false, $ordering, local_user()); if (!$update) { if (PConfig::get(local_user(), 'system', 'infinite_scroll')) { @@ -456,7 +456,7 @@ function networkFlatView(App $a, $update = 0) $items = q("SELECT %s FROM `item` $sql_post_table %s WHERE %s AND `item`.`uid` = %d ORDER BY `item`.`id` DESC $pager_sql ", - item_fieldlists(), item_joins(), item_condition(), + item_fieldlists(), item_joins($_SESSION['uid']), item_condition(), intval($_SESSION['uid']) ); @@ -774,12 +774,15 @@ function networkThreadedView(App $a, $update, $parent) AND (`item`.`parent-uri` != `item`.`uri` OR `contact`.`uid` = `item`.`uid` AND `contact`.`self` OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`) + LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` + AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) AND NOT `item`.`moderated` AND $sql_extra4 $sql_extra3 $sql_extra $sql_range $sql_nets ORDER BY `order_date` DESC LIMIT 100", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND), + intval(local_user()), intval(local_user()) ); } else { @@ -791,12 +794,15 @@ function networkThreadedView(App $a, $update, $parent) AND (`item`.`parent-uri` != `item`.`uri` OR `contact`.`uid` = `item`.`uid` AND `contact`.`self` OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`) + LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d WHERE `thread`.`uid` = %d AND `thread`.`visible` AND NOT `thread`.`deleted` AND NOT `thread`.`moderated` + AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) $sql_extra2 $sql_extra3 $sql_range $sql_extra $sql_nets ORDER BY `order_date` DESC $pager_sql", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND), + intval(local_user()), intval(local_user()) ); } diff --git a/mod/notes.php b/mod/notes.php index aa239fb0e0..96a2826089 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -82,7 +82,7 @@ function notes_content(App $a, $update = false) WHERE %s AND `item`.`uid` = %d AND `item`.`type` = 'note' AND `contact`.`self` AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall` $sql_extra ", - item_joins(), + item_joins(local_user()), item_condition(), intval(local_user()) ); @@ -97,7 +97,7 @@ function notes_content(App $a, $update = false) AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall` $sql_extra ORDER BY `item`.`created` DESC LIMIT %d ,%d ", - item_joins(), + item_joins(local_user()), item_condition(), intval(local_user()), intval($a->pager['start']), @@ -119,7 +119,7 @@ function notes_content(App $a, $update = false) $sql_extra ORDER BY `parent` DESC, `gravity` ASC, `item`.`id` ASC ", item_fieldlists(), - item_joins(), + item_joins(local_user()), item_condition(), intval(local_user()), dbesc($parents_str) diff --git a/mod/profile.php b/mod/profile.php index 2856cdd177..2af2845f27 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -339,7 +339,7 @@ function profile_content(App $a, $update = 0) $parents_str = implode(', ', $parents_arr); - $items = q(item_query() . " AND `item`.`uid` = %d + $items = q(item_query($a->profile['profile_uid']) . " AND `item`.`uid` = %d AND `item`.`parent` IN (%s) $sql_extra ", intval($a->profile['profile_uid']), diff --git a/mod/search.php b/mod/search.php index be0f943d07..4c461e4183 100644 --- a/mod/search.php +++ b/mod/search.php @@ -204,7 +204,7 @@ function search_content(App $a) { AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`term` = '%s' AND `item`.`verb` = '%s' AND NOT `author`.`blocked` AND NOT `author`.`hidden` ORDER BY term.created DESC LIMIT %d , %d ", - item_fieldlists(), item_joins(), item_condition(), + item_fieldlists(), item_joins(local_user()), item_condition(), intval(local_user()), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), dbesc(protect_sprintf($search)), dbesc(ACTIVITY_POST), intval($a->pager['start']), intval($a->pager['itemspage'])); @@ -219,7 +219,7 @@ function search_content(App $a) { AND NOT `author`.`blocked` AND NOT `author`.`hidden` $sql_extra GROUP BY `item`.`uri`, `item`.`id` ORDER BY `item`.`id` DESC LIMIT %d , %d", - item_fieldlists(), item_joins(), item_condition(), + item_fieldlists(), item_joins(local_user()), item_condition(), intval(local_user()), intval($a->pager['start']), intval($a->pager['itemspage'])); } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 6db786dfc8..41543d89cc 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -1786,6 +1786,17 @@ class DBStructure "username" => ["username(32)"], ] ]; + $database["user-item"] = [ + "comment" => "User specific item data", + "fields" => [ + "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["item" => "id"], "comment" => "Item id"], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["user" => "uid"], "comment" => "User id"], + "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hidden marker"], + ], + "indexes" => [ + "PRIMARY" => ["uid", "iid"], + ] + ]; $database["workerqueue"] = [ "comment" => "Background tasks queue entries", "fields" => [ diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 03f5a36db1..bbfb399238 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1049,7 +1049,7 @@ class Contact extends BaseObject $contact = ($r[0]["contact-type"] == ACCOUNT_TYPE_COMMUNITY ? 'owner-id' : 'author-id'); - $r = q(item_query() . " AND `item`.`" . $contact . "` = %d AND " . $sql . + $r = q(item_query(local_user()) . " AND `item`.`" . $contact . "` = %d AND " . $sql . " AND `item`.`verb` = '%s' ORDER BY `item`.`created` DESC LIMIT %d, %d", intval($author_id), intval(local_user()), dbesc(ACTIVITY_POST), intval($a->pager['start']), intval($a->pager['itemspage']) diff --git a/src/Model/Item.php b/src/Model/Item.php index 309ddd858d..91c889a1ed 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -201,8 +201,16 @@ class Item extends BaseObject // send the notification upstream/downstream Worker::add(['priority' => $priority, 'dont_fork' => true], "Notifier", "drop", intval($item['id'])); + } elseif ($item['uid'] != 0) { + + // When we delete just our local user copy of an item, we have to set an marker to hide it + $global_item = dba::selectFirst('item', ['id'], ['uri' => $item['uri'], 'uid' => 0, 'deleted' => false]); + if (DBM::is_result($global_item)) { + dba::update('user-item', ['hidden' => true], ['iid' => $global_item['id'], 'uid' => $item['uid']], true); + } } + logger('Item with ID ' . $item_id . " has been deleted.", LOGGER_DEBUG); return true;