-- ------------------------------------------
-- Friendica 2022.05-dev (Siberian Iris)
--- DB_UPDATE_VERSION 1457
+-- DB_UPDATE_VERSION 1458
-- ------------------------------------------
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
--
`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`,
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` 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`,
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` 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`,
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` 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`,
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`;
| [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 |
--- /dev/null
+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)
--- /dev/null
+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)
--- /dev/null
+<?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 : []);
+ }
+}
--- /dev/null
+<?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 : []);
+ }
+}
}
}
+ /**
+ * 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
*
$item = self::processContent($activity, $item);
self::storeAttachments($activity, $item);
+ self::storeQuestion($activity, $item);
if (empty($item)) {
return;
$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']);
$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'])) {
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'] = [];
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1457);
+ define('DB_UPDATE_VERSION', 1458);
}
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" => [
"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`"
],