aboutsummaryrefslogtreecommitdiffstats
path: root/include/items.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/items.php')
-rw-r--r--include/items.php457
1 files changed, 234 insertions, 223 deletions
diff --git a/include/items.php b/include/items.php
index 55d768e28..b80c5672b 100644
--- a/include/items.php
+++ b/include/items.php
@@ -4802,19 +4802,19 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
return $items;
}
-function webpage_to_namespace($webpage) {
+function item_type_to_namespace($item_type) {
- if($webpage == ITEM_TYPE_WEBPAGE)
+ if($item_type == ITEM_TYPE_WEBPAGE)
$page_type = 'WEBPAGE';
- elseif($webpage == ITEM_TYPE_BLOCK)
+ elseif($item_type == ITEM_TYPE_BLOCK)
$page_type = 'BUILDBLOCK';
- elseif($webpage == ITEM_TYPE_PDL)
+ elseif($item_type == ITEM_TYPE_PDL)
$page_type = 'PDL';
- elseif($webpage == ITEM_TYPE_CARD)
+ elseif($item_type == ITEM_TYPE_CARD)
$page_type = 'CARD';
- elseif($webpage == ITEM_TYPE_ARTICLE)
+ elseif($item_type == ITEM_TYPE_ARTICLE)
$page_type = 'ARTICLE';
- elseif($webpage == ITEM_TYPE_DOC)
+ elseif($item_type == ITEM_TYPE_DOC)
$page_type = 'docfile';
else
$page_type = 'unknown';
@@ -4823,12 +4823,12 @@ function webpage_to_namespace($webpage) {
}
-function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
+function update_remote_id($channel,$post_id,$item_type,$pagetitle,$namespace,$remote_id,$mid) {
if(! intval($post_id))
return;
- $page_type = webpage_to_namespace($webpage);
+ $page_type = item_type_to_namespace($item_type);
if($page_type == 'unknown' && $namespace && $remote_id) {
$page_type = $namespace;
@@ -5361,250 +5361,238 @@ function set_activity_mid($string) {
}
/**
- * @brief returns SQL which counts activities for an item and
- * if there is an observer also count activities authored by observer.
- * @param string $prefix (optional)
- */
-
-function item_activity_sql($prefix = 'c') {
- $sql = '';
- $observer = get_observer_hash();
-
- $thread_allow = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
-
- if ($observer) {
- $sql = <<<SQL
- COUNT(CASE WHEN $prefix.verb = 'Like' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_liked,
- COUNT(CASE WHEN $prefix.verb = 'Dislike' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_disliked,
- COUNT(CASE WHEN $prefix.verb = 'Announce' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_announced,
- COUNT(CASE WHEN $prefix.verb = 'Accept' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_accepted,
- COUNT(CASE WHEN $prefix.verb = 'Reject' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_rejected,
- COUNT(CASE WHEN $prefix.verb = 'TentativeAccept' AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_tentativelyaccepted,
- SQL;
-
- if ($thread_allow) {
- $sql .= " COUNT(CASE WHEN $prefix.verb IN ('Create','Update') AND $prefix.author_xchan = '$observer' THEN 1 END) AS observer_commented, ";
- }
- }
-
-
- if ($thread_allow) {
- $sql .= "COUNT(CASE WHEN $prefix.verb IN ('Create','Update') THEN 1 END) AS comment_count,";
- }
-
- $sql .= <<<SQL
- COUNT(CASE WHEN $prefix.verb = 'Like' THEN 1 END) AS like_count,
- COUNT(CASE WHEN $prefix.verb = 'Dislike' THEN 1 END) AS dislike_count,
- COUNT(CASE WHEN $prefix.verb = 'Announce' THEN 1 END) AS announce_count,
- COUNT(CASE WHEN $prefix.verb = 'Accept' THEN 1 END) AS attendyes_count,
- COUNT(CASE WHEN $prefix.verb = 'Reject' THEN 1 END) AS attendno_count,
- COUNT(CASE WHEN $prefix.verb = 'TentativeAccept' THEN 1 END) AS attendmaybe_count
- SQL;
-
- return $sql;
-
-}
-
-/**
- * @brief returns an item by id belonging to local_channel()
+ * @brief returns an item by id and parent belonging to local_channel()
* including activity counts.
* @param int $id
+ * @param int $parent
*/
-function item_by_item_id(int $id): array
+function item_by_item_id(int $id, int $parent): array
{
- if (!$id) {
+ if (!$id && !$parent && !local_channel()) {
return [];
}
- $item_normal = item_normal();
- $item_normal_c = item_normal(prefix: 'c');
- $activity_sql = item_activity_sql('c');
+ $item_normal_sql = item_normal();
+
+ $reaction = item_reaction_sql($parent);
+ $reaction_cte_sql = $reaction['cte'];
+ $reaction_select_sql = $reaction['select'];
+ $reaction_join_sql = $reaction['join'];
- $ret = q("SELECT item.*,
- $activity_sql
+ return q("WITH
+ $reaction_cte_sql
+ SELECT
+ *,
+ $reaction_select_sql
FROM item
- LEFT JOIN item c
- ON c.parent = item.parent
- AND c.item_thread_top = 0
- AND c.thr_parent = item.mid
- $item_normal_c
- WHERE item.id = $id
+ $reaction_join_sql
+ WHERE
+ item.id = %d
AND item.uid = %d
- $item_normal
- GROUP BY item.id",
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
+ $item_normal_sql",
+ intval($id),
intval(local_channel())
);
-
- return $ret;
}
+
/**
* @brief returns an array of items by ids
- * ATTENTION: no permissions for the pa are checked here!!!
- * Permissions MUST be checked by the function which returns the ids.
- * @param string $ids - a string with ids separated by comma
- * @param array $thr_parents (optional) - a string with thr_parent mids separated by comma
- * which will be included
- * @param string $permission_sql (optional) - SQL provided by item_permission_sql() from the calling module
+ * ATTENTION: no permissions for the parents are checked here!!!
+ * Permissions MUST be checked by the module which calls this function.
+ * @param array $parents
+ * @param null|array $thr_parents (optional) - thr_parent mids which will be included
+ * @param string $permission_sql (optional) - SQL as provided by item_permission_sql() from the calling module
* @param bool $blog_mode (optional) - if set to yes only the parent items will be returned
*/
-function items_by_parent_ids(string $ids, array $thr_parents = [], string $permission_sql = '', bool $blog_mode = false): array
+function items_by_parent_ids(array $parents, null|array $thr_parents = null, string $permission_sql = '', bool $blog_mode = false): array
{
- if (!$ids) {
+ if (!$parents) {
return [];
}
-
+ $ids = ids_to_querystr($parents, 'item_id');
$thread_allow = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
-
$item_normal_sql = item_normal();
- $activity_sql_cte = item_activity_sql_cte();
- $activity_sql_cte_sub = item_activity_sql_cte('sub');
+ $limit = $thread_allow ? 3 : 1000;
$thr_parent_sql = (($thread_allow) ? " AND item.thr_parent = item.parent_mid " : '');
-
if ($thr_parents && $thread_allow) {
+ $limit = 300;
$thr_parent_str = stringify_array($thr_parents, true);
$thr_parent_sql = " AND item.thr_parent IN (" . protect_sprintf($thr_parent_str) . ") ";
}
+ $reaction = item_reaction_sql($ids, $permission_sql, 'final_selection');
+ $reaction_cte_sql = $reaction['cte'];
+ $reaction_select_sql = $reaction['select'];
+ $reaction_join_sql = $reaction['join'];
+
if ($blog_mode) {
- $ret = q("SELECT item.*,
- $activity_sql_cte
- FROM item
- WHERE item.id IN (%s)
- $item_normal_sql
- $permission_sql",
- dbesc($ids)
- );
+ $q = <<<SQL
+ WITH
+ final_selection AS (
+ SELECT
+ item.*
+ FROM
+ item
+ WHERE
+ item.id IN ($ids)
+ ),
+
+ $reaction_cte_sql
+
+ SELECT
+ final_selection.*,
+ $reaction_select_sql
+ FROM final_selection
+ $reaction_join_sql
+ SQL;
+
+ return dbq(trim($q));
}
- else {
- $ret = q("WITH parents AS (
- SELECT item.*,
- 0 AS rn, -- this is required for union (equal amount of coulumns)
- $activity_sql_cte
+
+ $q = <<<SQL
+ WITH
+ parent_items AS (
+ SELECT
+ item.*,
+ 0 AS rn
FROM item
- WHERE item.id IN (%s)
- $item_normal_sql
+ WHERE
+ item.id IN ($ids)
+ ),
+
+ $reaction_cte_sql,
+
+ all_comments AS (
+ SELECT
+ item.*,
+ ROW_NUMBER() OVER (PARTITION BY item.parent ORDER BY item.created DESC) AS rn
+ FROM item
+ WHERE item.parent IN ($ids)
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
+ AND item.item_thread_top = 0
+ $thr_parent_sql
$permission_sql
- ),
- comments AS (
- SELECT sub.*,
- $activity_sql_cte_sub
- FROM (
- SELECT item.*,
- ROW_NUMBER() OVER (PARTITION BY item.parent ORDER BY item.created DESC) AS rn
- FROM item
- WHERE item.parent IN (%s)
- AND item.id != item.parent
- AND (
- item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept')
- OR (item.verb = 'Announce' AND item.item_thread_top = 1)
- )
- $thr_parent_sql
- $item_normal_sql
- $permission_sql
- ) sub
- WHERE rn <= 100 -- number of comments we want to load
- )
- SELECT * FROM parents
+ $item_normal_sql
+ ),
+
+ final_selection AS (
+ SELECT * FROM parent_items
UNION ALL
- SELECT * FROM comments",
- dbesc($ids),
- dbesc($ids)
- );
- }
+ SELECT * FROM all_comments WHERE all_comments.rn <= $limit
+ )
+
+ SELECT
+ final_selection.*,
+ $reaction_select_sql
+ FROM final_selection
+ $reaction_join_sql
+ SQL;
- return $ret;
+ return dbq(trim($q));
}
/**
- * @brief returns SQL which counts activities for an item and
- * if there is an observer also count activities authored by observer.
- * @param string $prefix (optional)
+ * @brief prepare reaction sql for items_by_parent_ids()
+ * ATTENTION: no permissions for the pa are checked here!!!
+ * Permissions MUST be checked by the function which returns the ids.
+ * @param string $ids
+ * @param string $permission_sql (optional) - SQL provided by item_permission_sql()
+ * @param string $join_prefix (optional) - prefix for the join part defaults to 'item'
*/
-function item_activity_sql_cte($prefix = 'item'): string
+function item_reaction_sql(string $ids, string $permission_sql = '', string $join_prefix = 'item'): array
{
- $thread_allow = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
+ $item_normal_sql = item_normal();
$observer = get_observer_hash();
- $sql = '';
-
- if ($observer) {
- $observer_verbs = [
- 'Like' => 'observer_liked',
- 'Dislike' => 'observer_disliked',
- 'Announce' => 'observer_announced',
- 'Accept' => 'observer_accepted',
- 'Reject' => 'observer_rejected',
- 'TentativeAccept' => 'observer_tentativelyaccepted'
- ];
- foreach($observer_verbs as $k => $v) {
- if ($sql) {
- $sql .= ",\n";
- }
+ $verbs = [
+ 'like' => ['Like'],
+ 'dislike' => ['Dislike'],
+ 'announce' => ['Announce'],
+ 'accept' => ['Accept'],
+ 'reject' => ['Reject'],
+ 'tentativeaccept' => ['TentativeAccept']
+ ];
- $sql .= <<<SQL
- (SELECT COUNT(*) FROM item AS reaction
- WHERE reaction.parent = $prefix.parent AND reaction.verb = '$k' AND reaction.author_xchan = '$observer' AND reaction.item_thread_top = 0 AND reaction.thr_parent = $prefix.mid
- ) AS $v
- SQL;
- }
+ $thread_allow = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
- if ($thread_allow) {
- $sql .= ",\n";
- $sql .= <<<SQL
- (SELECT COUNT(*) FROM item AS reaction
- WHERE reaction.parent = $prefix.parent AND reaction.verb IN ('Create', 'Update') AND reaction.author_xchan = '$observer' AND reaction.item_thread_top = 0 AND reaction.thr_parent = $prefix.mid
- ) AS observer_commented
- SQL;
- }
+ if ($thread_allow) {
+ $verbs['comment'] = ['Create', 'Update', 'EmojiReact'];
}
- $verbs = [
- 'Like' => 'like_count',
- 'Dislike' => 'dislike_count',
- 'Announce' => 'announce_count',
- 'Accept' => 'attendyes_count',
- 'Reject' => 'attendno_count',
- 'TentativeAccept' => 'attendmaybe_count'
- ];
+ $cte = '';
+ $select = '';
+ $join = '';
foreach($verbs as $k => $v) {
- if ($sql) {
- $sql .= ",\n";
+
+ $observer_sql = "0 AS observer_{$k}_count";
+ if ($observer) {
+ $observer_sql = "COUNT(CASE WHEN item.author_xchan = '$observer' THEN 1 END) AS observer_{$k}_count";
+ }
+
+ $verbs_str = stringify_array($v);
+
+ if ($cte) {
+ $cte .= ",\n";
}
- $sql .= <<<SQL
- (SELECT COUNT(*) FROM item AS reaction
- WHERE reaction.parent = $prefix.parent AND reaction.verb = '$k' AND reaction.item_thread_top = 0 AND reaction.thr_parent = $prefix.mid
- ) AS $v
+ $cte .= <<<SQL
+ reaction_{$k} AS (
+ SELECT
+ item.thr_parent,
+ -- COUNT(DISTINCT item.author_xchan) AS {$k}_count, (should we prevent multiple reactions by the same author?)
+ COUNT(*) AS {$k}_count,
+ $observer_sql
+ FROM item
+ WHERE item.verb IN ($verbs_str)
+ AND item.item_thread_top = 0
+ AND item.parent IN ($ids)
+ $item_normal_sql
+ $permission_sql
+ GROUP BY item.thr_parent
+ )
SQL;
- }
- if ($thread_allow) {
- $sql .= ",\n";
- $sql .= <<<SQL
- (SELECT COUNT(*) FROM item AS reaction
- WHERE reaction.parent = $prefix.parent AND reaction.verb IN ('Create', 'Update') AND reaction.item_thread_top = 0 AND reaction.thr_parent = $prefix.mid
- ) AS comment_count
+ if ($select) {
+ $select .= ",\n";
+ }
+
+ $select .= <<<SQL
+ COALESCE(reaction_{$k}.{$k}_count, 0) AS {$k}_count,
+ COALESCE(reaction_{$k}.observer_{$k}_count, 0) AS observer_{$k}_count
+ SQL;
+
+ $join .= <<<SQL
+ LEFT JOIN reaction_{$k} ON reaction_{$k}.thr_parent = $join_prefix.mid
SQL;
+
}
- return $sql;
+ $ret['cte'] = $cte;
+ $ret['select'] = $select;
+ $ret['join'] = $join;
+
+ return $ret;
}
+
+
/**
* @brief returns an array of items by thr_parent mid of a parent
* @param string $mid
* @param int $parent
+ * @param int|null $offset
*/
-function items_by_thr_parent(string $mid, int $parent): array
+function items_by_thr_parent(string $mid, int $parent, int|null $offset = null): array
{
if (!$mid && !$parent) {
return [];
@@ -5614,63 +5602,75 @@ function items_by_thr_parent(string $mid, int $parent): array
intval($parent)
);
- $owner_uid = intval($parent_item[0]['uid']);
+ $order_sql = "ORDER BY item.created";
+ if (isset($offset)) {
+ $order_sql = "ORDER BY item.created DESC, item.received DESC LIMIT 3 OFFSET $offset";
+ }
- $item_normal = item_normal($owner_uid);
- $item_normal_c = item_normal($owner_uid, 'c');
- $activity_sql = item_activity_sql('c');
+ $owner_uid = intval($parent_item[0]['uid']);
+ $item_normal_sql = item_normal($owner_uid);
if (local_channel() === $owner_uid) {
- $ret = q(
- "SELECT item.*,
- $activity_sql
+ $reaction = item_reaction_sql($parent);
+ $reaction_cte_sql = $reaction['cte'];
+ $reaction_select_sql = $reaction['select'];
+ $reaction_join_sql = $reaction['join'];
+
+ $ret = q("WITH
+ $reaction_cte_sql
+ SELECT
+ item.*,
+ $reaction_select_sql
FROM item
- LEFT JOIN item c ON c.parent = item.parent
- AND c.item_thread_top = 0
- AND c.thr_parent = item.mid
- $item_normal_c
- WHERE item.thr_parent = '%s'
+ $reaction_join_sql
+ WHERE
+ item.thr_parent = '%s'
AND item.uid = %d
- AND item.parent = %d
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
AND item.item_thread_top = 0
- $item_normal
- GROUP BY item.id
- ORDER BY item.created",
+ $item_normal_sql
+ $order_sql",
dbesc($mid),
- intval(local_channel()),
- intval($parent)
+ intval($owner_uid)
);
}
-
- if (!$ret) {
+ else {
$observer_hash = get_observer_hash();
- $sql_extra = item_permissions_sql($owner_uid, $observer_hash);
-
- $ret = q(
- "SELECT item.*,
- $activity_sql
+ $permission_sql = item_permissions_sql($owner_uid, $observer_hash);
+
+ $reaction = item_reaction_sql($parent, $permission_sql);
+ $reaction_cte_sql = $reaction['cte'];
+ $reaction_select_sql = $reaction['select'];
+ $reaction_join_sql = $reaction['join'];
+
+ $ret = q("WITH
+ $reaction_cte_sql
+ SELECT
+ item.*,
+ $reaction_select_sql
FROM item
- LEFT JOIN item c ON c.parent = item.parent
- AND c.item_thread_top = 0
- AND c.thr_parent = item.mid
- $item_normal_c
- WHERE item.thr_parent = '%s'
+ $reaction_join_sql
+ WHERE
+ item.thr_parent = '%s'
AND item.uid = %d
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
AND item.item_thread_top = 0
- $sql_extra
- $item_normal
- GROUP BY item.id
- ORDER BY item.created",
+ $permission_sql
+ $item_normal_sql
+ $order_sql",
dbesc($mid),
intval($owner_uid)
);
}
+ if (isset($offset)) {
+ $ret = array_reverse($ret);
+ }
+
return $ret;
}
+
/**
* @brief returns an array of xchan entries (partly) for activities of an item by mid of a parent.
* Also checks if observer is allowed to add activities to the item.
@@ -5702,6 +5702,7 @@ function item_activity_xchans(string $mid, int $parent, string $verb): array
AND item.verb = '%s'
AND item.item_thread_top = 0
$item_normal
+ -- GROUP BY item.author_xchan (should we prevent multiple reactions by the same author?)
ORDER BY item.created",
intval(local_channel()),
intval($parent),
@@ -5709,8 +5710,7 @@ function item_activity_xchans(string $mid, int $parent, string $verb): array
dbesc($verb)
);
}
-
- if (!$ret) {
+ else {
$sql_extra = item_permissions_sql($owner_uid, $observer_hash);
$ret = q("SELECT item.id, item.item_blocked, xchan.xchan_hash, xchan.xchan_name as name, xchan.xchan_url as url, xchan.xchan_photo_s as photo FROM item
@@ -5721,6 +5721,7 @@ function item_activity_xchans(string $mid, int $parent, string $verb): array
AND item.item_thread_top = 0
$sql_extra
$item_normal
+ -- GROUP BY item.author_xchan (should we prevent multiple reactions by the same author?)
ORDER BY item.created",
intval($owner_uid),
dbesc($mid),
@@ -5740,8 +5741,13 @@ function item_activity_xchans(string $mid, int $parent, string $verb): array
* @param array $item
*/
-function get_recursive_thr_parents(array $item): array
+function get_recursive_thr_parents(array $item): array|null
{
+ if ($item['id'] === $item['parent']) {
+ // This is a toplevel post, return null.
+ return null;
+ }
+
$thr_parents[] = $item['thr_parent'];
$mid = $item['thr_parent'];
@@ -5755,8 +5761,13 @@ function get_recursive_thr_parents(array $item): array
dbesc($mid)
);
+ if (!$x) {
+ break;
+ }
+
$mid = $x[0]['thr_parent'];
$thr_parents[] = $x[0]['thr_parent'];
+
$i++;
}