]> git.mxchange.org Git - friendica.git/commitdiff
We can now store incoming questions
authorMichael <heluecht@pirati.ca>
Wed, 20 Apr 2022 06:28:02 +0000 (06:28 +0000)
committerMichael <heluecht@pirati.ca>
Wed, 20 Apr 2022 06:28:02 +0000 (06:28 +0000)
database.sql
doc/database.md
doc/database/db_post-question-option.md [new file with mode: 0644]
doc/database/db_post-question.md [new file with mode: 0644]
src/Model/Post/Question.php [new file with mode: 0644]
src/Model/Post/QuestionOption.php [new file with mode: 0644]
src/Protocol/ActivityPub/Processor.php
src/Protocol/ActivityPub/Receiver.php
static/dbstructure.config.php
static/dbview.config.php

index 78fd9620e292afdec4e1ebabc0438f4d8ff9ddaa..48a75377fe94b99fb5430644fbed98f82a5f547e 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2022.05-dev (Siberian Iris)
--- DB_UPDATE_VERSION 1457
+-- DB_UPDATE_VERSION 1458
 -- ------------------------------------------
 
 
@@ -1161,6 +1161,32 @@ CREATE TABLE IF NOT EXISTS `post-media` (
        FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Attached media';
 
+--
+-- TABLE post-question
+--
+CREATE TABLE IF NOT EXISTS `post-question` (
+       `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
+       `uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
+       `multiple` boolean NOT NULL DEFAULT '0' COMMENT 'Multiple choice',
+       `voters` int unsigned COMMENT 'Number of voters for this question',
+       `end-time` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Question end time',
+        PRIMARY KEY(`id`),
+        UNIQUE INDEX `uri-id` (`uri-id`),
+       FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Question';
+
+--
+-- TABLE post-question-option
+--
+CREATE TABLE IF NOT EXISTS `post-question-option` (
+       `id` int unsigned NOT NULL COMMENT 'Id of the question',
+       `uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
+       `name` varchar(255) COMMENT 'Name of the option',
+       `replies` int unsigned COMMENT 'Number of replies for this question option',
+        PRIMARY KEY(`uri-id`,`id`),
+       FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Question option';
+
 --
 -- TABLE post-tag
 --
@@ -1720,6 +1746,10 @@ CREATE VIEW `post-user-view` AS SELECT
        `event`.`type` AS `event-type`,
        `event`.`nofinish` AS `event-nofinish`,
        `event`.`ignore` AS `event-ignore`,
+       `post-question`.`id` AS `question-id`,
+       `post-question`.`multiple` AS `question-multiple`,
+       `post-question`.`voters` AS `question-voters`,
+       `post-question`.`end-time` AS `question-end-time`,
        `diaspora-interaction`.`interaction` AS `signed_text`,
        `parent-item-uri`.`guid` AS `parent-guid`,
        `parent-post`.`network` AS `parent-network`,
@@ -1745,6 +1775,7 @@ CREATE VIEW `post-user-view` AS SELECT
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-user`.`uri-id` AND `post-user`.`origin`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-user`.`psid`
                        LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`;
@@ -1880,6 +1911,10 @@ CREATE VIEW `post-thread-user-view` AS SELECT
        `event`.`type` AS `event-type`,
        `event`.`nofinish` AS `event-nofinish`,
        `event`.`ignore` AS `event-ignore`,
+       `post-question`.`id` AS `question-id`,
+       `post-question`.`multiple` AS `question-multiple`,
+       `post-question`.`voters` AS `question-voters`,
+       `post-question`.`end-time` AS `question-end-time`,
        `diaspora-interaction`.`interaction` AS `signed_text`,
        `parent-item-uri`.`guid` AS `parent-guid`,
        `parent-post`.`network` AS `parent-network`,
@@ -1904,6 +1939,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-thread-user`.`uri-id` AND `post-thread-user`.`origin`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid`
                        LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-thread-user`.`uid`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`;
@@ -2006,6 +2042,10 @@ CREATE VIEW `post-view` AS SELECT
        `causer`.`blocked` AS `causer-blocked`,
        `causer`.`hidden` AS `causer-hidden`,
        `causer`.`contact-type` AS `causer-contact-type`,
+       `post-question`.`id` AS `question-id`,
+       `post-question`.`multiple` AS `question-multiple`,
+       `post-question`.`voters` AS `question-voters`,
+       `post-question`.`end-time` AS `question-end-time`,
        `diaspora-interaction`.`interaction` AS `signed_text`,
        `parent-item-uri`.`guid` AS `parent-guid`,
        `parent-post`.`network` AS `parent-network`,
@@ -2027,6 +2067,7 @@ CREATE VIEW `post-view` AS SELECT
                        LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post`.`uri-id`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post`.`uri-id`
                        LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`;
 
@@ -2128,6 +2169,10 @@ CREATE VIEW `post-thread-view` AS SELECT
        `causer`.`blocked` AS `causer-blocked`,
        `causer`.`hidden` AS `causer-hidden`,
        `causer`.`contact-type` AS `causer-contact-type`,
+       `post-question`.`id` AS `question-id`,
+       `post-question`.`multiple` AS `question-multiple`,
+       `post-question`.`voters` AS `question-voters`,
+       `post-question`.`end-time` AS `question-end-time`,
        `diaspora-interaction`.`interaction` AS `signed_text`,
        `parent-item-uri`.`guid` AS `parent-guid`,
        `parent-post`.`network` AS `parent-network`,
@@ -2149,6 +2194,7 @@ CREATE VIEW `post-thread-view` AS SELECT
                        LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread`.`uri-id`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id`
                        LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`;
 
index d436dcc32bcc577047ec2aaa94170f55367741e2..629a86ee0a1c827ba865afc20a305d58272a20f5 100644 (file)
@@ -52,6 +52,8 @@ Database Tables
 | [post-delivery-data](help/database/db_post-delivery-data) | Delivery data for items |
 | [post-link](help/database/db_post-link) | Post related external links |
 | [post-media](help/database/db_post-media) | Attached media |
+| [post-question](help/database/db_post-question) | Question |
+| [post-question-option](help/database/db_post-question-option) | Question option |
 | [post-tag](help/database/db_post-tag) | post relation to tags |
 | [post-thread](help/database/db_post-thread) | Thread related data |
 | [post-thread-user](help/database/db_post-thread-user) | Thread related data per user |
diff --git a/doc/database/db_post-question-option.md b/doc/database/db_post-question-option.md
new file mode 100644 (file)
index 0000000..0dd10ac
--- /dev/null
@@ -0,0 +1,30 @@
+Table post-question-option
+===========
+
+Question option
+
+Fields
+------
+
+| Field   | Description                                               | Type         | Null | Key | Default | Extra |
+| ------- | --------------------------------------------------------- | ------------ | ---- | --- | ------- | ----- |
+| id      | Id of the question                                        | int unsigned | NO   | PRI | NULL    |       |
+| uri-id  | Id of the item-uri table entry that contains the item uri | int unsigned | NO   | PRI | NULL    |       |
+| name    | Name of the option                                        | varchar(255) | YES  |     | NULL    |       |
+| replies | Number of replies for this question option                | int unsigned | YES  |     | NULL    |       |
+
+Indexes
+------------
+
+| Name    | Fields     |
+| ------- | ---------- |
+| PRIMARY | uri-id, id |
+
+Foreign Keys
+------------
+
+| Field | Target Table | Target Field |
+|-------|--------------|--------------|
+| uri-id | [item-uri](help/database/db_item-uri) | id |
+
+Return to [database documentation](help/database)
diff --git a/doc/database/db_post-question.md b/doc/database/db_post-question.md
new file mode 100644 (file)
index 0000000..8f637ff
--- /dev/null
@@ -0,0 +1,32 @@
+Table post-question
+===========
+
+Question
+
+Fields
+------
+
+| Field    | Description                                               | Type         | Null | Key | Default             | Extra          |
+| -------- | --------------------------------------------------------- | ------------ | ---- | --- | ------------------- | -------------- |
+| id       | sequential ID                                             | int unsigned | NO   | PRI | NULL                | auto_increment |
+| uri-id   | Id of the item-uri table entry that contains the item uri | int unsigned | NO   |     | NULL                |                |
+| multiple | Multiple choice                                           | boolean      | NO   |     | 0                   |                |
+| voters   | Number of voters for this question                        | int unsigned | YES  |     | NULL                |                |
+| end-time | Question end time                                         | datetime     | YES  |     | 0001-01-01 00:00:00 |                |
+
+Indexes
+------------
+
+| Name    | Fields         |
+| ------- | -------------- |
+| PRIMARY | id             |
+| uri-id  | UNIQUE, uri-id |
+
+Foreign Keys
+------------
+
+| Field | Target Table | Target Field |
+|-------|--------------|--------------|
+| uri-id | [item-uri](help/database/db_item-uri) | id |
+
+Return to [database documentation](help/database)
diff --git a/src/Model/Post/Question.php b/src/Model/Post/Question.php
new file mode 100644 (file)
index 0000000..949ff2e
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Model\Post;
+
+use \BadMethodCallException;
+use Friendica\Database\Database;
+use Friendica\Database\DBA;
+use Friendica\Database\DBStructure;
+
+class Question
+{
+       /**
+        * Update a post question entry
+        *
+        * @param integer $uri_id
+        * @param array   $data
+        * @param bool    $insert_if_missing
+        * @return bool
+        * @throws \Exception
+        */
+       public static function update(int $uri_id, array $data = [], bool $insert_if_missing = true)
+       {
+               if (empty($uri_id)) {
+                       throw new BadMethodCallException('Empty URI_id');
+               }
+
+               $fields = DBStructure::getFieldsForTable('post-question', $data);
+
+               // Remove the key fields
+               unset($fields['uri-id']);
+
+               if (empty($fields)) {
+                       return true;
+               }
+
+               return DBA::update('post-question', $fields, ['uri-id' => $uri_id], $insert_if_missing ? true : []);
+       }
+}
diff --git a/src/Model/Post/QuestionOption.php b/src/Model/Post/QuestionOption.php
new file mode 100644 (file)
index 0000000..d5e82d5
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Model\Post;
+
+use \BadMethodCallException;
+use Friendica\Database\Database;
+use Friendica\Database\DBA;
+use Friendica\Database\DBStructure;
+
+class QuestionOption
+{
+       /**
+        * Update a post question-option entry
+        *
+        * @param integer $uri_id
+        * @param integer $id
+        * @param array   $data
+        * @param bool    $insert_if_missing
+        * @return bool
+        * @throws \Exception
+        */
+       public static function update(int $uri_id, int $id, array $data = [], bool $insert_if_missing = true)
+       {
+               if (empty($uri_id)) {
+                       throw new BadMethodCallException('Empty URI_id');
+               }
+
+               $fields = DBStructure::getFieldsForTable('post-question-option', $data);
+
+               // Remove the key fields
+               unset($fields['uri-id']);
+               unset($fields['id']);
+
+               if (empty($fields)) {
+                       return true;
+               }
+
+               return DBA::update('post-question-option', $fields, ['uri-id' => $uri_id, 'id' => $id], $insert_if_missing ? true : []);
+       }
+}
index 8bd08b95b48c93e6e47eecef7f15b9ddd2794ad8..be17ea469c55c9959e2eaa2868f522aeaa4a0861 100644 (file)
@@ -152,6 +152,37 @@ class Processor
                }
        }
 
+       /**
+        * Store attachment data
+        *
+        * @param array   $activity
+        * @param array   $item
+        */
+       private static function storeQuestion($activity, $item)
+       {
+               if (empty($activity['question'])) {
+                       return;
+               }
+               $question = ['multiple' => $activity['question']['multiple']];
+
+               if (!empty($activity['question']['voters'])) {
+                       $question['voters'] = $activity['question']['voters'];
+               }
+
+               if (!empty($activity['question']['end-time'])) {
+                       $question['end-time'] = $activity['question']['end-time'];
+               }
+
+               Post\Question::update($item['uri-id'], $question);
+
+               foreach ($activity['question']['options'] as $key => $option) {
+                       $option = ['name' => $option['name'], 'replies' => $option['replies']];
+                       Post\QuestionOption::update($item['uri-id'], $key, $option);
+               }
+
+               Logger::debug('Storing incoming question', ['type' => $activity['type'], 'uri-id' => $item['uri-id'], 'question' => $activity['question']]);
+       }
+
        /**
         * Updates a message
         *
@@ -178,6 +209,7 @@ class Processor
                $item = self::processContent($activity, $item);
 
                self::storeAttachments($activity, $item);
+               self::storeQuestion($activity, $item);
 
                if (empty($item)) {
                        return;
@@ -347,6 +379,7 @@ class Processor
                $item['plink'] = $activity['alternate-url'] ?? $item['uri'];
 
                self::storeAttachments($activity, $item);
+               self::storeQuestion($activity, $item);
 
                // We received the post via AP, so we set the protocol of the server to AP
                $contact = Contact::getById($item['author-id'], ['gsid']);
index 6cd0111ec0f59e2d3df5a1d1f6064c9db86cf33e..c8d131b7257589741222b96f1253a1990058ecec 100644 (file)
@@ -553,12 +553,13 @@ class Receiver
                        $object_data['from-relay'] = $activity['from-relay'];
                }
 
+               if (in_array('as:Question', [$object_data['object_type'] ?? '', $object_data['object_object_type'] ?? ''])) {
+                       self::storeUnhandledActivity(false, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
+               }
+
                switch ($type) {
                        case 'as:Create':
                                if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
-                                       if ($object_data['object_type'] == 'as:Question') {
-                                               self::storeUnhandledActivity(false, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);
-                                       }
                                        $item = ActivityPub\Processor::createItem($object_data);
                                        ActivityPub\Processor::postItem($object_data, $item);
                                } elseif (in_array($object_data['object_type'], ['pt:CacheFile'])) {
@@ -1460,7 +1461,13 @@ class Receiver
                        return [];
                }
 
-               // @todo Check if "closed" is a thing, see here: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-closed
+               $closed = JsonLD::fetchElement($object, 'as:closed', '@value');
+               if (!empty($closed)) {
+                       $question['end-time'] = $closed;
+               } else {
+                       $question['end-time'] = JsonLD::fetchElement($object, 'as:endTime', '@value');
+               }
+
                $question['voters']  = (int)JsonLD::fetchElement($object, 'toot:votersCount', '@value');
                $question['options'] = [];
 
index aea48375668a3ba449eca4b05450c9d139a8af5f..8c2f4dcf907d45456e0ab2223aac5589cbb12264 100644 (file)
@@ -55,7 +55,7 @@
 use Friendica\Database\DBA;
 
 if (!defined('DB_UPDATE_VERSION')) {
-       define('DB_UPDATE_VERSION', 1457);
+       define('DB_UPDATE_VERSION', 1458);
 }
 
 return [
@@ -1202,6 +1202,32 @@ return [
                        "uri-id-url" => ["UNIQUE", "uri-id", "url"],
                ]
        ],
+       "post-question" => [
+               "comment" => "Question",
+               "fields" => [
+                       "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                       "uri-id" => ["type" => "int unsigned", "not null" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"],
+                       "multiple" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Multiple choice"],
+                       "voters" => ["type" => "int unsigned", "comment" => "Number of voters for this question"],
+                       "end-time" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => "Question end time"],
+               ],
+               "indexes" => [
+                       "PRIMARY" => ["id"],
+                       "uri-id" => ["UNIQUE", "uri-id"],
+               ]
+       ],
+       "post-question-option" => [
+               "comment" => "Question option",
+               "fields" => [
+                       "id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => "Id of the question"],
+                       "uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"],
+                       "name" => ["type" => "varchar(255)", "comment" => "Name of the option"],
+                       "replies" => ["type" => "int unsigned", "comment" => "Number of replies for this question option"],
+               ],
+               "indexes" => [
+                       "PRIMARY" => ["uri-id", "id"],
+               ]
+       ],
        "post-tag" => [
                "comment" => "post relation to tags",
                "fields" => [
index 9083185d5aac1f3eb9ff70938f00523697496cdf..82ccaa9d1259c12eaf92647c9bf1ee232b3ed0d7 100644 (file)
                        "event-type" => ["event", "type"],
                        "event-nofinish" => ["event", "nofinish"],
                        "event-ignore" => ["event", "ignore"],
+                       "question-id" => ["post-question", "id"],
+                       "question-multiple" => ["post-question", "multiple"],
+                       "question-voters" => ["post-question", "voters"],
+                       "question-end-time" => ["post-question", "end-time"],
                        "signed_text" => ["diaspora-interaction", "interaction"],
                        "parent-guid" => ["parent-item-uri", "guid"],
                        "parent-network" => ["parent-post", "network"],
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-user`.`uri-id` AND `post-user`.`origin`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-user`.`uri-id`
                        LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-user`.`psid`
                        LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`"
                        "event-type" => ["event", "type"],
                        "event-nofinish" => ["event", "nofinish"],
                        "event-ignore" => ["event", "ignore"],
+                       "question-id" => ["post-question", "id"],
+                       "question-multiple" => ["post-question", "multiple"],
+                       "question-voters" => ["post-question", "voters"],
+                       "question-end-time" => ["post-question", "end-time"],
                        "signed_text" => ["diaspora-interaction", "interaction"],
                        "parent-guid" => ["parent-item-uri", "guid"],
                        "parent-network" => ["parent-post", "network"],
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-thread-user`.`uri-id` AND `post-thread-user`.`origin`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread-user`.`uri-id`
                        LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid`
                        LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-thread-user`.`uid`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`"
                        "causer-blocked" => ["causer", "blocked"],
                        "causer-hidden" => ["causer", "hidden"],
                        "causer-contact-type" => ["causer", "contact-type"],
+                       "question-id" => ["post-question", "id"],
+                       "question-multiple" => ["post-question", "multiple"],
+                       "question-voters" => ["post-question", "voters"],
+                       "question-end-time" => ["post-question", "end-time"],
                        "signed_text" => ["diaspora-interaction", "interaction"],
                        "parent-guid" => ["parent-item-uri", "guid"],
                        "parent-network" => ["parent-post", "network"],
                        LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post`.`uri-id`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post`.`uri-id`
                        LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`"
        ],
                        "causer-blocked" => ["causer", "blocked"],
                        "causer-hidden" => ["causer", "hidden"],
                        "causer-contact-type" => ["causer", "contact-type"],
+                       "question-id" => ["post-question", "id"],
+                       "question-multiple" => ["post-question", "multiple"],
+                       "question-voters" => ["post-question", "voters"],
+                       "question-end-time" => ["post-question", "end-time"],
                        "signed_text" => ["diaspora-interaction", "interaction"],
                        "parent-guid" => ["parent-item-uri", "guid"],
                        "parent-network" => ["parent-post", "network"],
                        LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
                        LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread`.`uri-id`
                        LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread`.`uri-id`
+                       LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id`
                        LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id`
                        LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`"
        ],