From d383f49f1efaca841e78afdfa31d1952a7cce433 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 6 Nov 2020 04:14:29 +0000 Subject: [PATCH 01/17] The "[attach]" field is replaced by the "post-media" table --- src/Model/Item.php | 12 ++--- src/Model/Post/Media.php | 11 +++- src/Module/Diaspora/Fetch.php | 2 +- src/Protocol/ActivityPub/Transmitter.php | 67 ++++++------------------ src/Protocol/DFRN.php | 30 ++++------- src/Protocol/Diaspora.php | 12 ++--- src/Protocol/OStatus.php | 28 ++++------ 7 files changed, 58 insertions(+), 104 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 088f783d6a..25af1ce542 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -3651,12 +3651,10 @@ class Item $as = ''; $vhead = false; - $matches = []; - preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\"(?: title=\"(.*?)\")?|', $item['attach'], $matches, PREG_SET_ORDER); - foreach ($matches as $mtch) { - $mime = $mtch[3]; + foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) { + $mime = $attachment['mimetype']; - $the_url = Contact::magicLinkById($item['author-id'], $mtch[1]); + $the_url = Contact::magicLinkById($item['author-id'], $attachment['url']); if (strpos($mime, 'video') !== false) { if (!$vhead) { @@ -3683,8 +3681,8 @@ class Item $filesubtype = 'unkn'; } - $title = Strings::escapeHtml(trim(($mtch[4] ?? '') ?: $mtch[1])); - $title .= ' ' . $mtch[2] . ' ' . DI::l10n()->t('bytes'); + $title = Strings::escapeHtml(trim(($attachment['description'] ?? '') ?: $attachment['url'])); + $title .= ' ' . ($attachment['size'] ?? 0) . ' ' . DI::l10n()->t('bytes'); $icon = '
'; $as .= '' . $icon . ''; diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 57668fa99e..1a9d4a83ea 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -263,11 +263,18 @@ class Media * Retrieves the media attachments associated with the provided item ID. * * @param int $uri_id + * @param array $types * @return array * @throws \Exception */ - public static function getByURIId(int $uri_id) + public static function getByURIId(int $uri_id, array $types = []) { - return DBA::selectToArray('post-media', [], ['uri-id' => $uri_id]); + $condition = ['uri-id' => $uri_id]; + + if (!empty($types)) { + $condition = DBA::mergeConditions($condition, ['type' => $types]); + } + + return DBA::selectToArray('post-media', [], $condition); } } diff --git a/src/Module/Diaspora/Fetch.php b/src/Module/Diaspora/Fetch.php index c94badf7e3..028d7e452e 100644 --- a/src/Module/Diaspora/Fetch.php +++ b/src/Module/Diaspora/Fetch.php @@ -52,7 +52,7 @@ class Fetch extends BaseModule // Fetch the item $fields = [ 'uid', 'title', 'body', 'guid', 'contact-id', 'private', 'created', 'received', 'app', 'location', 'coord', 'network', - 'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'attach' + 'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'attach', 'uri-id' ]; $condition = ['wall' => true, 'private' => [Item::PUBLIC, Item::UNLISTED], 'guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]]; $item = Item::selectFirst($fields, $condition); diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 0044b5240b..bb11019b5b 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -37,13 +37,13 @@ use Friendica\Model\Item; use Friendica\Model\ItemURI; use Friendica\Model\Profile; use Friendica\Model\Photo; +use Friendica\Model\Post; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; use Friendica\Util\DateTimeFormat; use Friendica\Util\HTTPSignature; -use Friendica\Util\Images; use Friendica\Util\JsonLD; use Friendica\Util\LDSignature; use Friendica\Util\Map; @@ -1220,57 +1220,22 @@ class Transmitter $attachments[] = $attachment; } */ - $arr = explode('[/attach],', $item['attach']); - if (count($arr)) { - foreach ($arr as $r) { - $matches = false; - $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|', $r, $matches); - if ($cnt) { - $attributes = ['type' => 'Document', - 'mediaType' => $matches[3], - 'url' => $matches[1], - 'name' => null]; - - if (trim($matches[4]) != '') { - $attributes['name'] = trim($matches[4]); - } - - $attachments[] = $attributes; - } - } + foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) { + $attachments[] = ['type' => 'Document', + 'mediaType' => $attachment['mimetype'], + 'url' => $attachment['url'], + 'name' => $attachment['description']]; } if ($type != 'Note') { return $attachments; } - // Simplify image codes - $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $item['body']); - - // Grab all pictures without alternative descriptions and create attachments out of them - if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures)) { - foreach ($pictures[1] as $picture) { - $imgdata = Images::getInfoFromURLCached($picture); - if ($imgdata) { - $attachments[] = ['type' => 'Document', - 'mediaType' => $imgdata['mime'], - 'url' => $picture, - 'name' => null]; - } - } - } - - // Grab all pictures with alternative description and create attachments out of them - if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { - foreach ($pictures as $picture) { - $imgdata = Images::getInfoFromURLCached($picture[1]); - if ($imgdata) { - $attachments[] = ['type' => 'Document', - 'mediaType' => $imgdata['mime'], - 'url' => $picture[1], - 'name' => $picture[2]]; - } - } + foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]) as $attachment) { + $attachments[] = ['type' => 'Document', + 'mediaType' => $attachment['mimetype'], + 'url' => $attachment['url'], + 'name' => $attachment['description']]; } return $attachments; @@ -1454,16 +1419,16 @@ class Transmitter $body = $item['body']; - if (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) { - $body = self::prependMentions($body, $item['uri-id']); - } - if ($type == 'Note') { - $body = self::removePictures($body); + $body = $item['raw-body'] ?? self::removePictures($body); } elseif (($type == 'Article') && empty($data['summary'])) { $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($body), 1000)); } + if (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) { + $body = self::prependMentions($body, $item['uri-id']); + } + if ($type == 'Event') { $data = array_merge($data, self::createEvent($item)); } else { diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 2f5cd2effd..629962b97b 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -866,27 +866,19 @@ class DFRN */ private static function getAttachment($doc, $root, $item) { - $arr = explode('[/attach],', $item['attach']); - if (count($arr)) { - foreach ($arr as $r) { - $matches = false; - $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|', $r, $matches); - if ($cnt) { - $attributes = ["rel" => "enclosure", - "href" => $matches[1], - "type" => $matches[3]]; + foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) { + $attributes = ['rel' => 'enclosure', + 'href' => $attachment['url'], + 'type' => $attachment['mimetype']]; - if (intval($matches[2])) { - $attributes["length"] = intval($matches[2]); - } - - if (trim($matches[4]) != "") { - $attributes["title"] = trim($matches[4]); - } - - XML::addElement($doc, $root, "link", "", $attributes); - } + if (!empty($attachment['size'])) { + $attributes['length'] = intval($attachment['size']); } + if (!empty($attachment['description'])) { + $attributes['title'] = $attachment['description']; + } + + XML::addElement($doc, $root, 'link', '', $attributes); } } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index c9a02a4fce..1077238f71 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -3578,13 +3578,11 @@ class Diaspora $body = "### ".html_entity_decode($title)."\n\n".$body; } - if ($item["attach"]) { - $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism', $item["attach"], $matches, PREG_SET_ORDER); - if ($cnt) { - $body .= "\n".DI::l10n()->t("Attachments:")."\n"; - foreach ($matches as $mtch) { - $body .= "[".$mtch[3]."](".$mtch[1].")\n"; - } + $attachments = Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]); + if (!empty($attachments)) { + $body .= "\n".DI::l10n()->t("Attachments:")."\n"; + foreach ($attachments as $attachment) { + $body .= "[" . $attachment['description'] . "](" . $attachment['url'] . ")\n"; } } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 5c157c9805..e27e34b6b4 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1392,25 +1392,19 @@ class OStatus } } - $arr = explode('[/attach],', $item['attach']); - if (count($arr)) { - foreach ($arr as $r) { - $matches = false; - $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|', $r, $matches); - if ($cnt) { - $attributes = ["rel" => "enclosure", - "href" => $matches[1], - "type" => $matches[3]]; + foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) { + $attributes = ['rel' => 'enclosure', + 'href' => $attachment['url'], + 'type' => $attachment['mimetype']]; - if (intval($matches[2])) { - $attributes["length"] = intval($matches[2]); - } - if (trim($matches[4]) != "") { - $attributes["title"] = trim($matches[4]); - } - XML::addElement($doc, $root, "link", "", $attributes); - } + if (!empty($attachment['size'])) { + $attributes['length'] = intval($attachment['size']); } + if (!empty($attachment['description'])) { + $attributes['title'] = $attachment['description']; + } + + XML::addElement($doc, $root, 'link', '', $attributes); } } From 43749c306966ffb5bb9fa41d58afa23914e43bbc Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 08:22:59 +0000 Subject: [PATCH 02/17] The "attach" field is now deprecated --- database.sql | 2 +- include/api.php | 47 +++++++++++++----------- src/Model/Contact.php | 2 - src/Model/Item.php | 27 ++++++++------ src/Model/Post/Media.php | 16 ++++++++ src/Module/Diaspora/Fetch.php | 2 +- src/Module/Like.php | 5 +-- src/Protocol/ActivityPub/Processor.php | 21 ++--------- src/Protocol/ActivityPub/Transmitter.php | 1 - src/Protocol/DFRN.php | 15 +++----- src/Protocol/Diaspora.php | 10 ++--- src/Protocol/Feed.php | 26 ++++++------- src/Protocol/OStatus.php | 13 ++----- static/dbstructure.config.php | 3 +- 14 files changed, 91 insertions(+), 99 deletions(-) diff --git a/database.sql b/database.sql index d3e75e753e..5e9104b7a2 100644 --- a/database.sql +++ b/database.sql @@ -677,7 +677,7 @@ CREATE TABLE IF NOT EXISTS `item` ( `psid` int unsigned COMMENT 'ID of the permission set of this post', `resource-id` varchar(32) NOT NULL DEFAULT '' COMMENT 'Used to link other tables to items, it identifies the linked resource (e.g. photo) and if set must also set resource_type', `event-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Used to link to the event.id', - `attach` mediumtext COMMENT 'JSON structure representing attachments to this item', + `attach` mediumtext COMMENT 'Deprecated', `allow_cid` mediumtext COMMENT 'Deprecated', `allow_gid` mediumtext COMMENT 'Deprecated', `deny_cid` mediumtext COMMENT 'Deprecated', diff --git a/include/api.php b/include/api.php index 86fdeead2f..09184dcf91 100644 --- a/include/api.php +++ b/include/api.php @@ -2040,35 +2040,40 @@ function api_statuses_repeat($type) Logger::log('API: api_statuses_repeat: '.$id); - $fields = ['uri-id', 'body', 'title', 'attach', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $fields = ['uri-id', 'network', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; $item = Item::selectFirst($fields, ['id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED]]); if (DBA::isResult($item) && $item['body'] != "") { - if (strpos($item['body'], "[/share]") !== false) { - $pos = strpos($item['body'], "[share"); - $post = substr($item['body'], $pos); + if (in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::TWITTER])) { + if (!Item::performActivity($id, 'announce', local_user())) { + throw new InternalServerErrorException(); + } + + $item_id = $id; } else { - $post = BBCode::getShareOpeningTag($item['author-name'], $item['author-link'], $item['author-avatar'], $item['plink'], $item['created'], $item['guid']); + if (strpos($item['body'], "[/share]") !== false) { + $pos = strpos($item['body'], "[share"); + $post = substr($item['body'], $pos); + } else { + $post = BBCode::getShareOpeningTag($item['author-name'], $item['author-link'], $item['author-avatar'], $item['plink'], $item['created'], $item['guid']); - if (!empty($item['title'])) { - $post .= '[h3]' . $item['title'] . "[/h3]\n"; + if (!empty($item['title'])) { + $post .= '[h3]' . $item['title'] . "[/h3]\n"; + } + + $post .= $item['body']; + $post .= "[/share]"; + } + $_REQUEST['body'] = $post; + $_REQUEST['profile_uid'] = api_user(); + $_REQUEST['api_source'] = true; + + if (empty($_REQUEST['source'])) { + $_REQUEST["source"] = api_source(); } - $post .= $item['body']; - $post .= "[/share]"; + $item_id = item_post($a); } - $_REQUEST['body'] = $post; - $_REQUEST['attach'] = $item['attach']; - $_REQUEST['profile_uid'] = api_user(); - $_REQUEST['api_source'] = true; - - if (empty($_REQUEST['source'])) { - $_REQUEST["source"] = api_source(); - } - - $item_id = item_post($a); - - /// @todo Copy tags from the original post to the new one } else { throw new ForbiddenException(); } diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 74a9619c2f..67b9c90383 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -754,7 +754,6 @@ class Contact $item['title'] = ''; $item['guid'] = ''; $item['uri-id'] = 0; - $item['attach'] = ''; $slap = OStatus::salmon($item, $user); if (!empty($contact['notify'])) { @@ -2233,7 +2232,6 @@ class Contact $item['title'] = ''; $item['guid'] = ''; $item['uri-id'] = 0; - $item['attach'] = ''; $slap = OStatus::salmon($item, $owner); diff --git a/src/Model/Item.php b/src/Model/Item.php index 25af1ce542..834a1c218d 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -77,7 +77,7 @@ class Item const DISPLAY_FIELDLIST = [ 'uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', 'network', 'gravity', 'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink', - 'wall', 'private', 'starred', 'origin', 'title', 'body', 'file', 'attach', 'language', + 'wall', 'private', 'starred', 'origin', 'title', 'body', 'file', 'language', 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'item_id', 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', @@ -95,7 +95,7 @@ class Item const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', 'parent-guid', 'created', 'edited', 'verb', 'object-type', 'object', 'target', 'private', 'title', 'body', 'location', 'coord', 'app', - 'attach', 'deleted', 'extid', 'post-type', 'gravity', + 'deleted', 'extid', 'post-type', 'gravity', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'author-id', 'author-link', 'owner-link', 'contact-uid', 'signed_text', 'signature', 'signer', 'network']; @@ -113,7 +113,7 @@ class Item 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'vid', 'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'psid', 'created', 'edited', 'commented', 'received', 'changed', 'verb', - 'postopts', 'plink', 'resource-id', 'event-id', 'attach', 'inform', + 'postopts', 'plink', 'resource-id', 'event-id', 'inform', 'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'network', @@ -659,7 +659,7 @@ class Item 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'vid', 'causer-id', 'contact-id', 'owner-id', 'author-id', 'type', 'wall', 'gravity', 'extid', 'created', 'edited', 'commented', 'received', 'changed', 'psid', - 'resource-id', 'event-id', 'attach', 'post-type', 'file', + 'resource-id', 'event-id', 'post-type', 'file', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'id' => 'item_id', 'network', 'icid', @@ -1087,7 +1087,7 @@ class Item Logger::info('Mark item for deletion by id', ['id' => $item_id, 'callstack' => System::callstack()]); // locate item to be deleted $fields = ['id', 'uri', 'uri-id', 'uid', 'parent', 'parent-uri', 'origin', - 'deleted', 'file', 'resource-id', 'event-id', 'attach', + 'deleted', 'file', 'resource-id', 'event-id', 'verb', 'object-type', 'object', 'target', 'contact-id', 'icid', 'psid', 'gravity']; $item = self::selectFirst($fields, ['id' => $item_id]); @@ -1144,10 +1144,9 @@ class Item } // If item has attachments, drop them - /// @TODO: this should first check if attachment is used elsewhere - foreach (explode(",", $item['attach']) as $attach) { - preg_match("|attach/(\d+)|", $attach, $matches); - if (is_array($matches) && count($matches) > 1) { + $attachments = Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT]); + foreach($attachments as $attachment) { + if (preg_match("|attach/(\d+)|", $attachment['url'], $matches)) { Attach::delete(['id' => $matches[1], 'uid' => $item['uid']]); } } @@ -1693,7 +1692,6 @@ class Item $item['private'] = intval($item['private'] ?? self::PUBLIC); $item['body'] = trim($item['body'] ?? ''); $item['raw-body'] = trim($item['raw-body'] ?? $item['body']); - $item['attach'] = trim($item['attach'] ?? ''); $item['app'] = trim($item['app'] ?? ''); $item['origin'] = intval($item['origin'] ?? 0); $item['postopts'] = trim($item['postopts'] ?? ''); @@ -2857,14 +2855,19 @@ class Item } if ($contact['network'] != Protocol::FEED) { + $old_uri_id = $datarray["uri-id"] ?? 0; $datarray["guid"] = System::createUUID(); unset($datarray["plink"]); $datarray["uri"] = self::newURI($contact['uid'], $datarray["guid"]); + $datarray["uri-id"] = ItemURI::getIdByURI($datarray["uri"]); $datarray["parent-uri"] = $datarray["uri"]; $datarray["thr-parent"] = $datarray["uri"]; $datarray["extid"] = Protocol::DFRN; $urlpart = parse_url($datarray2['author-link']); $datarray["app"] = $urlpart["host"]; + if (!empty($old_uri_id)) { + Post\Media::copy($old_uri_id, $datarray["uri-id"]); + } } else { $datarray['private'] = self::PUBLIC; } @@ -3921,7 +3924,7 @@ class Item $uid = $item['uid'] ?? 0; // first try to fetch the item via the GUID. This will work for all reshares that had been created on this system - $shared_item = self::selectFirst(['title', 'body', 'attach'], ['guid' => $shared['guid'], 'uid' => [0, $uid]]); + $shared_item = self::selectFirst(['title', 'body'], ['guid' => $shared['guid'], 'uid' => [0, $uid]]); if (!DBA::isResult($shared_item)) { if (empty($shared['link'])) { return $item; @@ -3934,7 +3937,7 @@ class Item return $item; } - $shared_item = self::selectFirst(['title', 'body', 'attach'], ['id' => $id]); + $shared_item = self::selectFirst(['title', 'body'], ['id' => $id]); if (!DBA::isResult($shared_item)) { return $item; } diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 1a9d4a83ea..441fd52767 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -86,6 +86,22 @@ class Media } } + /** + * Copy attachments from one uri-id to another + * + * @param integer $from_uri_id + * @param integer $to_uri_id + * @return void + */ + public static function copy(int $from_uri_id, int $to_uri_id) + { + $attachments = self::getByURIId($from_uri_id); + foreach ($attachments as $attachment) { + $attachment['uri-id'] = $to_uri_id; + self::insert($attachment); + } + } + /** * Creates the "[attach]" element from the given attributes * diff --git a/src/Module/Diaspora/Fetch.php b/src/Module/Diaspora/Fetch.php index 028d7e452e..67f6fd0f7e 100644 --- a/src/Module/Diaspora/Fetch.php +++ b/src/Module/Diaspora/Fetch.php @@ -52,7 +52,7 @@ class Fetch extends BaseModule // Fetch the item $fields = [ 'uid', 'title', 'body', 'guid', 'contact-id', 'private', 'created', 'received', 'app', 'location', 'coord', 'network', - 'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'attach', 'uri-id' + 'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'uri-id' ]; $condition = ['wall' => true, 'private' => [Item::PUBLIC, Item::UNLISTED], 'guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]]; $item = Item::selectFirst($fields, $condition); diff --git a/src/Module/Like.php b/src/Module/Like.php index ea6f20e165..4a6831b738 100644 --- a/src/Module/Like.php +++ b/src/Module/Like.php @@ -54,7 +54,7 @@ class Like extends BaseModule // @TODO: Replace with parameter from router $itemId = (($app->argc > 1) ? Strings::escapeTags(trim($app->argv[1])) : 0); - if (in_array($verb, [ 'announce', 'unannounce'])) { + if (in_array($verb, ['announce', 'unannounce'])) { $item = Item::selectFirst(['network'], ['id' => $itemId]); if ($item['network'] == Protocol::DIASPORA) { self::performDiasporaReshare($itemId); @@ -85,7 +85,7 @@ class Like extends BaseModule private static function performDiasporaReshare(int $itemId) { - $fields = ['uri-id', 'body', 'title', 'attach', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $fields = ['uri-id', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; $item = Item::selectFirst($fields, ['id' => $itemId, 'private' => [Item::PUBLIC, Item::UNLISTED]]); if (!DBA::isResult($item) || ($item['body'] == '')) { return; @@ -105,7 +105,6 @@ class Like extends BaseModule $post .= '[/share]'; } $_REQUEST['body'] = $post; - $_REQUEST['attach'] = $item['attach']; $_REQUEST['profile_uid'] = local_user(); require_once 'mod/item.php'; diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 5af712fc78..bd7735f5ae 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -135,8 +135,6 @@ class Processor return $item; } - $item['attach'] = ''; - foreach ($activity['attachments'] as $attach) { switch ($attach['type']) { case 'link': @@ -189,21 +187,6 @@ class Processor } $item['body'] .= "\n[video]" . $attach['url'] . '[/video]'; - } elseif (!empty($attach['url'])) { - if (!empty($item['attach'])) { - $item['attach'] .= ','; - } else { - $item['attach'] = ''; - } - - $item['attach'] .= Post\Media::getAttachElement( - $attach['url'], - $attach['length'] ?? 0, - $attach['mediaType'] ?? '', - $attach['name'] ?? '' - ); - } else { - Logger::notice('Unknown attachment', ['attach' => $attach]); } } } @@ -787,6 +770,10 @@ class Processor $object_actor = $object['actor']; } elseif (!empty($object['attributedTo'])) { $object_actor = $object['attributedTo']; + if (is_array($object_actor)) { + $compacted = JsonLD::compact($object); + $object_actor = JsonLD::fetchElement($compacted, 'as:attributedTo', '@id'); + } } else { // Shouldn't happen $object_actor = ''; diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index bb11019b5b..f5ef35337a 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -829,7 +829,6 @@ class Transmitter $mail['gravity'] = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT); $mail['event-type'] = ''; - $mail['attach'] = ''; $mail['parent'] = 0; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 629962b97b..11c4e3a14d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -2146,9 +2146,9 @@ class DFRN { $rel = ""; $href = ""; - $type = ""; - $length = "0"; - $title = ""; + $type = null; + $length = null; + $title = null; foreach ($links as $link) { foreach ($link->attributes as $attributes) { switch ($attributes->name) { @@ -2165,13 +2165,8 @@ class DFRN $item["plink"] = $href; break; case "enclosure": - if (!empty($item["attach"])) { - $item["attach"] .= ","; - } else { - $item["attach"] = ""; - } - - $item["attach"] .= Post\Media::getAttachElement($href, $length, $type, $title); + Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::DOCUMENT, + 'url' => $href, 'mimetype' => $type, 'size' => $length, 'description' => $title]); break; } } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 1077238f71..8c93d7c0f2 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -2458,8 +2458,8 @@ class Diaspora } // Do we already have this item? - $fields = ['body', 'title', 'attach', 'app', 'created', 'object-type', 'uri', 'guid', - 'author-name', 'author-link', 'author-avatar', 'plink']; + $fields = ['body', 'title', 'app', 'created', 'object-type', 'uri', 'guid', + 'author-name', 'author-link', 'author-avatar', 'plink', 'uri-id']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); @@ -2502,8 +2502,8 @@ class Diaspora } if ($stored) { - $fields = ['body', 'title', 'attach', 'app', 'created', 'object-type', 'uri', 'guid', - 'author-name', 'author-link', 'author-avatar', 'plink']; + $fields = ['body', 'title', 'app', 'created', 'object-type', 'uri', 'guid', + 'author-name', 'author-link', 'author-avatar', 'plink', 'uri-id']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); @@ -2646,7 +2646,7 @@ class Diaspora Tag::storeFromBody($datarray['uri-id'], $datarray["body"]); - $datarray["attach"] = $original_item["attach"]; + Post\Media::copy($original_item['uri-id'], $datarray['uri-id']); $datarray["app"] = $original_item["app"]; $datarray["plink"] = self::plink($author, $guid); diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index ff35e97505..89e7d75423 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -437,8 +437,8 @@ class Feed $enclosures = $xpath->query("enclosure|atom:link[@rel='enclosure']", $entry); foreach ($enclosures AS $enclosure) { $href = ""; - $length = 0; - $type = ""; + $length = null; + $type = null; foreach ($enclosure->attributes AS $attribute) { if (in_array($attribute->name, ["url", "href"])) { @@ -450,15 +450,9 @@ class Feed } } - if (!empty($item["attach"])) { - $item["attach"] .= ','; - } else { - $item["attach"] = ''; + if (!empty($href)) { + $attachments[] = ['type' => Post\Media::DOCUMENT, 'url' => $href, 'mimetype' => $type, 'size' => $length]; } - - $attachments[] = ["link" => $href, "type" => $type, "length" => $length]; - - $item["attach"] .= Post\Media::getAttachElement($href, $length, $type); } $taglist = []; @@ -515,8 +509,8 @@ class Feed if (!empty($contact["fetch_further_information"]) && ($contact["fetch_further_information"] < 3)) { // Handle enclosures and treat them as preview picture foreach ($attachments AS $attachment) { - if ($attachment["type"] == "image/jpeg") { - $preview = $attachment["link"]; + if ($attachment["mimetype"] == "image/jpeg") { + $preview = $attachment["url"]; } } @@ -576,7 +570,7 @@ class Feed $item["body"] = $item["body"] . "\n" . PageInfo::getFooterFromData($data, false); $taglist = $contact["fetch_further_information"] == 2 ? PageInfo::getTagsFromUrl($item["plink"], $preview, $contact["ffi_keyword_denylist"] ?? '') : []; $item["object-type"] = Activity\ObjectType::BOOKMARK; - unset($item["attach"]); + $attachments = []; } else { if (!empty($summary)) { $item["body"] = '[abstract]' . HTML::toBBCode($summary, $basepath) . "[/abstract]\n" . $item["body"]; @@ -616,11 +610,15 @@ class Feed Logger::info("Feed for contact " . $contact["url"] . " stored under id " . $id); - if (!empty($id) && !empty($taglist)) { + if (!empty($id) && (!empty($taglist) || !empty($attachments))) { $feeditem = Item::selectFirst(['uri-id'], ['id' => $id]); foreach ($taglist as $tag) { Tag::store($feeditem['uri-id'], Tag::HASHTAG, $tag); } + foreach ($attachments as $attachment) { + $attachment['uri-id'] = $feeditem['uri-id']; + Post\Media::insert($attachment); + } } } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index e27e34b6b4..e394877b35 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1119,16 +1119,9 @@ class OStatus if ($filetype == 'image') { $link_data['add_body'] .= "\n[img]".$attribute['href'].'[/img]'; } else { - if (!empty($item["attach"])) { - $item["attach"] .= ','; - } else { - $item["attach"] = ''; - } - if (!isset($attribute['length'])) { - $attribute['length'] = "0"; - } - $item["attach"] .= Post\Media::getAttachElement($attribute['href'], - $attribute['length'], $attribute['type'], $attribute['title'] ?? ''); + Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::DOCUMENT, + 'url' => $attribute['href'], 'mimetype' => $attribute['type'], + 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); } break; case "related": diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index a3b94e0b27..7df84f81ab 100755 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -747,9 +747,8 @@ return [ // It has to be decided whether these fields belong to the user or the structure "resource-id" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => "Used to link other tables to items, it identifies the linked resource (e.g. photo) and if set must also set resource_type"], "event-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["event" => "id"], "comment" => "Used to link to the event.id"], - // Could possibly be replaced by the "attach" table? - "attach" => ["type" => "mediumtext", "comment" => "JSON structure representing attachments to this item"], // Deprecated fields. Will be removed in upcoming versions + "attach" => ["type" => "mediumtext", "comment" => "Deprecated"], "allow_cid" => ["type" => "mediumtext", "comment" => "Deprecated"], "allow_gid" => ["type" => "mediumtext", "comment" => "Deprecated"], "deny_cid" => ["type" => "mediumtext", "comment" => "Deprecated"], From 3a5cdecb621ffc67d56882f16b0c274ec22b9243 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 09:02:02 +0000 Subject: [PATCH 03/17] New function to fetch the database driver --- src/Database/DBA.php | 10 +++++ src/Database/Database.php | 79 +++++++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/Database/DBA.php b/src/Database/DBA.php index babc4500eb..7dd7ac3e3a 100644 --- a/src/Database/DBA.php +++ b/src/Database/DBA.php @@ -72,6 +72,16 @@ class DBA return DI::dba()->getConnection(); } + /** + * Return the database driver string + * + * @return string with either "pdo" or "mysqli" + */ + public static function getDriver() + { + return DI::dba()->getDriver(); + } + /** * Returns the MySQL server version string * diff --git a/src/Database/Database.php b/src/Database/Database.php index c4d30df15e..273c2985c6 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -39,6 +39,9 @@ use Psr\Log\LoggerInterface; */ class Database { + const PDO = 'pdo'; + const MYSQLI = 'mysqli'; + protected $connected = false; /** @@ -119,7 +122,7 @@ class Database $this->pdo_emulate_prepares = (bool)$this->configCache->get('database', 'pdo_emulate_prepares'); if (!$this->configCache->get('database', 'disable_pdo') && class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { - $this->driver = 'pdo'; + $this->driver = self::PDO; $connect = "mysql:host=" . $server . ";dbname=" . $db; if ($port > 0) { @@ -140,7 +143,7 @@ class Database } if (!$this->connected && class_exists('\mysqli')) { - $this->driver = 'mysqli'; + $this->driver = self::MYSQLI; if ($port > 0) { $this->connection = @new mysqli($server, $user, $pass, $db, $port); @@ -201,10 +204,10 @@ class Database { if (!is_null($this->connection)) { switch ($this->driver) { - case 'pdo': + case self::PDO: $this->connection = null; break; - case 'mysqli': + case self::MYSQLI: $this->connection->close(); $this->connection = null; break; @@ -234,6 +237,16 @@ class Database return $this->connection; } + /** + * Return the database driver string + * + * @return string with either "pdo" or "mysqli" + */ + public function getDriver() + { + return $this->driver; + } + /** * Returns the MySQL server version string * @@ -246,10 +259,10 @@ class Database { if ($this->server_info == '') { switch ($this->driver) { - case 'pdo': + case self::PDO: $this->server_info = $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION); break; - case 'mysqli': + case self::MYSQLI: $this->server_info = $this->connection->server_info; break; } @@ -346,10 +359,10 @@ class Database { if ($this->connected) { switch ($this->driver) { - case 'pdo': + case self::PDO: return substr(@$this->connection->quote($str, PDO::PARAM_STR), 1, -1); - case 'mysqli': + case self::MYSQLI: return @$this->connection->real_escape_string($str); } } else { @@ -371,14 +384,14 @@ class Database } switch ($this->driver) { - case 'pdo': + case self::PDO: $r = $this->p("SELECT 1"); if ($this->isResult($r)) { $row = $this->toArray($r); $connected = ($row[0]['1'] == '1'); } break; - case 'mysqli': + case self::MYSQLI: $connected = $this->connection->ping(); break; } @@ -508,7 +521,7 @@ class Database } switch ($this->driver) { - case 'pdo': + case self::PDO: // If there are no arguments we use "query" if ($this->emulate_prepares || count($args) == 0) { if (!$retval = $this->connection->query($this->replaceParameters($sql, $args))) { @@ -553,7 +566,7 @@ class Database $this->affected_rows = $retval->rowCount(); } break; - case 'mysqli': + case self::MYSQLI: // There are SQL statements that cannot be executed with a prepared statement $parts = explode(' ', $orig_sql); $command = strtolower($parts[0]); @@ -861,9 +874,9 @@ class Database return 0; } switch ($this->driver) { - case 'pdo': + case self::PDO: return $stmt->columnCount(); - case 'mysqli': + case self::MYSQLI: return $stmt->field_count; } return 0; @@ -882,9 +895,9 @@ class Database return 0; } switch ($this->driver) { - case 'pdo': + case self::PDO: return $stmt->rowCount(); - case 'mysqli': + case self::MYSQLI: return $stmt->num_rows; } return 0; @@ -909,10 +922,10 @@ class Database } switch ($this->driver) { - case 'pdo': + case self::PDO: $columns = $stmt->fetch(PDO::FETCH_ASSOC); break; - case 'mysqli': + case self::MYSQLI: if (get_class($stmt) == 'mysqli_result') { $columns = $stmt->fetch_assoc(); break; @@ -1023,10 +1036,10 @@ class Database public function lastInsertId() { switch ($this->driver) { - case 'pdo': + case self::PDO: $id = $this->connection->lastInsertId(); break; - case 'mysqli': + case self::MYSQLI: $id = $this->connection->insert_id; break; } @@ -1046,7 +1059,7 @@ class Database public function lock($table) { // See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html - if ($this->driver == 'pdo') { + if ($this->driver == self::PDO) { $this->e("SET autocommit=0"); $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); } else { @@ -1055,12 +1068,12 @@ class Database $success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE"); - if ($this->driver == 'pdo') { + if ($this->driver == self::PDO) { $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); } if (!$success) { - if ($this->driver == 'pdo') { + if ($this->driver == self::PDO) { $this->e("SET autocommit=1"); } else { $this->connection->autocommit(true); @@ -1082,13 +1095,13 @@ class Database // See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html $this->performCommit(); - if ($this->driver == 'pdo') { + if ($this->driver == self::PDO) { $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); } $success = $this->e("UNLOCK TABLES"); - if ($this->driver == 'pdo') { + if ($this->driver == self::PDO) { $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); $this->e("SET autocommit=1"); } else { @@ -1111,13 +1124,13 @@ class Database } switch ($this->driver) { - case 'pdo': + case self::PDO: if (!$this->connection->inTransaction() && !$this->connection->beginTransaction()) { return false; } break; - case 'mysqli': + case self::MYSQLI: if (!$this->connection->begin_transaction()) { return false; } @@ -1131,14 +1144,14 @@ class Database protected function performCommit() { switch ($this->driver) { - case 'pdo': + case self::PDO: if (!$this->connection->inTransaction()) { return true; } return $this->connection->commit(); - case 'mysqli': + case self::MYSQLI: return $this->connection->commit(); } @@ -1169,7 +1182,7 @@ class Database $ret = false; switch ($this->driver) { - case 'pdo': + case self::PDO: if (!$this->connection->inTransaction()) { $ret = true; break; @@ -1177,7 +1190,7 @@ class Database $ret = $this->connection->rollBack(); break; - case 'mysqli': + case self::MYSQLI: $ret = $this->connection->rollback(); break; } @@ -1634,10 +1647,10 @@ class Database } switch ($this->driver) { - case 'pdo': + case self::PDO: $ret = $stmt->closeCursor(); break; - case 'mysqli': + case self::MYSQLI: // MySQLi offers both a mysqli_stmt and a mysqli_result class. // We should be careful not to assume the object type of $stmt // because DBA::p() has been able to return both types. From 9d804f655e439de94c62d004e9bf149bc231ca66 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 09:02:21 +0000 Subject: [PATCH 04/17] Database text no checks for database driver --- tests/functional/DependencyCheckTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index d1c85bdd0e..6e4f519e00 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -119,6 +119,7 @@ class DependencyCheckTest extends TestCase $database = $this->dice->create(Database::class); self::assertInstanceOf(Database::class, $database); + self::assertContains($database->getDriver(), [Database::PDO, Database::MYSQLI]); self::assertTrue($database->connected()); } From 8baac6121270a17778579178eb944f2367e7e820 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 09:37:57 +0000 Subject: [PATCH 05/17] Test connection --- tests/functional/DependencyCheckTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 6e4f519e00..1d98a18246 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -120,6 +120,7 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(Database::class, $database); self::assertContains($database->getDriver(), [Database::PDO, Database::MYSQLI]); + self::assertNotNull($database->getConnection()); self::assertTrue($database->connected()); } From d6a1a836f1ce0613b9d17f26a1f0fe778d50aa52 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 09:58:20 +0000 Subject: [PATCH 06/17] Simplified connection test --- src/Database/Database.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 273c2985c6..f8ef1c9a1e 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -386,10 +386,11 @@ class Database switch ($this->driver) { case self::PDO: $r = $this->p("SELECT 1"); - if ($this->isResult($r)) { - $row = $this->toArray($r); - $connected = ($row[0]['1'] == '1'); - } + $connected = $this->isResult($r); +// if ($this->isResult($r)) { +// $row = $this->toArray($r); +// $connected = ($row[0]['1'] == '1'); +// } break; case self::MYSQLI: $connected = $this->connection->ping(); From 84924d1c051c23d3b40a09446564de81b07b9d58 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 10:12:31 +0000 Subject: [PATCH 07/17] Test the tes --- src/Database/Database.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index f8ef1c9a1e..f74241c42c 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -386,14 +386,14 @@ class Database switch ($this->driver) { case self::PDO: $r = $this->p("SELECT 1"); - $connected = $this->isResult($r); -// if ($this->isResult($r)) { -// $row = $this->toArray($r); -// $connected = ($row[0]['1'] == '1'); -// } + if ($this->isResult($r)) { + $row = $this->toArray($r); + $connected = ($row[0]['1'] == '1'); + } break; case self::MYSQLI: - $connected = $this->connection->ping(); + $connected = true; + // $connected = $this->connection->ping(); break; } From 8906615b2c5716555cfd6e321790b7a26837c240 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 10:27:22 +0000 Subject: [PATCH 08/17] Test if PDO doesn't work on the tests --- src/Database/Database.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index f74241c42c..4ca454821b 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -385,15 +385,15 @@ class Database switch ($this->driver) { case self::PDO: - $r = $this->p("SELECT 1"); - if ($this->isResult($r)) { - $row = $this->toArray($r); - $connected = ($row[0]['1'] == '1'); - } + $connected = true; +// $r = $this->p("SELECT 1"); +// if ($this->isResult($r)) { +// $row = $this->toArray($r); +// $connected = ($row[0]['1'] == '1'); +// } break; case self::MYSQLI: - $connected = true; - // $connected = $this->connection->ping(); + $connected = $this->connection->ping(); break; } From 2ba0d884a0a45a9bdb88db05faa90e849a0f970c Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 10:45:38 +0000 Subject: [PATCH 09/17] Added mode tests --- tests/functional/DependencyCheckTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 1d98a18246..00b8afbffa 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -131,7 +131,12 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(App\Mode::class, $mode); - self::assertTrue($mode->isNormal()); + self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT), 'No local config present'); + self::assertTrue($mode->has((App\Mode::DBAVAILABLE), 'Database is not available'); + self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE), 'Database config is not available'); + self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED), 'In maintenance mode'); + + self::assertTrue($mode->isNormal(), 'Not in normal mode'); } public function testConfiguration() From dadd73ba3198cd136cbed0a7b89617e2b16165d6 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 10:46:08 +0000 Subject: [PATCH 10/17] Syntax error fixed --- tests/functional/DependencyCheckTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 00b8afbffa..050e446458 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -131,10 +131,10 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(App\Mode::class, $mode); - self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT), 'No local config present'); - self::assertTrue($mode->has((App\Mode::DBAVAILABLE), 'Database is not available'); - self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE), 'Database config is not available'); - self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED), 'In maintenance mode'); + self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT), 'No local config present')); + self::assertTrue($mode->has((App\Mode::DBAVAILABLE), 'Database is not available')); + self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE), 'Database config is not available')); + self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED), 'In maintenance mode')); self::assertTrue($mode->isNormal(), 'Not in normal mode'); } From 335a122c813d12713ce379f4b08364f39585d4ec Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 11:02:23 +0000 Subject: [PATCH 11/17] The tests had been split --- tests/functional/DependencyCheckTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 050e446458..2fb4c7d5d8 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -136,7 +136,7 @@ class DependencyCheckTest extends TestCase self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE), 'Database config is not available')); self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED), 'In maintenance mode')); - self::assertTrue($mode->isNormal(), 'Not in normal mode'); + // self::assertTrue($mode->isNormal(), 'Not in normal mode'); } public function testConfiguration() From 1e52c430e606cf3bc1ef7593bba11e41bf21992e Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 11:26:56 +0000 Subject: [PATCH 12/17] Fix assertion messages --- tests/functional/DependencyCheckTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 2fb4c7d5d8..4694f3d0ed 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -131,12 +131,12 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(App\Mode::class, $mode); - self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT), 'No local config present')); - self::assertTrue($mode->has((App\Mode::DBAVAILABLE), 'Database is not available')); - self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE), 'Database config is not available')); - self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED), 'In maintenance mode')); + self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT)), 'No local config present'); + self::assertTrue($mode->has((App\Mode::DBAVAILABLE)), 'Database is not available'); + self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE)), 'Database config is not available'); + self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED)), 'In maintenance mode'); - // self::assertTrue($mode->isNormal(), 'Not in normal mode'); + self::assertTrue($mode->isNormal(), 'Not in normal mode'); } public function testConfiguration() From eb8caaa5e794fdf0d4e855744832850a079f0035 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 11:44:39 +0000 Subject: [PATCH 13/17] Restore the connection check --- src/Database/Database.php | 11 +++++------ tests/functional/DependencyCheckTest.php | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 4ca454821b..273c2985c6 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -385,12 +385,11 @@ class Database switch ($this->driver) { case self::PDO: - $connected = true; -// $r = $this->p("SELECT 1"); -// if ($this->isResult($r)) { -// $row = $this->toArray($r); -// $connected = ($row[0]['1'] == '1'); -// } + $r = $this->p("SELECT 1"); + if ($this->isResult($r)) { + $row = $this->toArray($r); + $connected = ($row[0]['1'] == '1'); + } break; case self::MYSQLI: $connected = $this->connection->ping(); diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 4694f3d0ed..fcb16e14cc 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -119,9 +119,9 @@ class DependencyCheckTest extends TestCase $database = $this->dice->create(Database::class); self::assertInstanceOf(Database::class, $database); - self::assertContains($database->getDriver(), [Database::PDO, Database::MYSQLI]); - self::assertNotNull($database->getConnection()); - self::assertTrue($database->connected()); + self::assertContains($database->getDriver(), [Database::PDO, Database::MYSQLI], 'The driver returns an unexpected value'); + self::assertNotNull($database->getConnection(), 'There is no database connection'); + self::assertTrue($database->connected(), 'The database is not connected'); } public function testAppMode() From 9b95722fba02e3360bf59b280b5a9043c07e7b53 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 12:45:04 +0000 Subject: [PATCH 14/17] Removed unneded parentheses --- tests/functional/DependencyCheckTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index fcb16e14cc..8c1c5ac93e 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -131,10 +131,10 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(App\Mode::class, $mode); - self::assertTrue($mode->has((App\Mode::LOCALCONFIGPRESENT)), 'No local config present'); - self::assertTrue($mode->has((App\Mode::DBAVAILABLE)), 'Database is not available'); - self::assertTrue($mode->has((App\Mode::DBCONFIGAVAILABLE)), 'Database config is not available'); - self::assertTrue($mode->has((App\Mode::MAINTENANCEDISABLED)), 'In maintenance mode'); + self::assertTrue($mode->has(App\Mode::LOCALCONFIGPRESENT), 'No local config present'); + self::assertTrue($mode->has(App\Mode::DBAVAILABLE), 'Database is not available'); + self::assertTrue($mode->has(App\Mode::DBCONFIGAVAILABLE), 'Database config is not available'); + self::assertTrue($mode->has(App\Mode::MAINTENANCEDISABLED), 'In maintenance mode'); self::assertTrue($mode->isNormal(), 'Not in normal mode'); } From efc29694500f4b5f77347744e5d1e3b5cefbed16 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 14:53:50 +0000 Subject: [PATCH 15/17] Test if the tests work better without PDO --- tests/Util/AppMockTrait.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Util/AppMockTrait.php b/tests/Util/AppMockTrait.php index c6f07897c6..c6d730d0fe 100644 --- a/tests/Util/AppMockTrait.php +++ b/tests/Util/AppMockTrait.php @@ -141,6 +141,10 @@ trait AppMockTrait ->shouldReceive('get') ->with('database', 'database') ->andReturn(getenv('MYSQL_DATABASE')); + $this->configMock + ->shouldReceive('get') + ->with('database', 'disable_pdo') + ->andReturn(true); $this->configMock ->shouldReceive('get') ->with('config', 'hostname') From 23a68803a1e95a989bf28eb59c6806229e49d453 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 7 Nov 2020 15:25:43 +0000 Subject: [PATCH 16/17] Remove PDO test --- tests/Util/AppMockTrait.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/Util/AppMockTrait.php b/tests/Util/AppMockTrait.php index c6d730d0fe..c6f07897c6 100644 --- a/tests/Util/AppMockTrait.php +++ b/tests/Util/AppMockTrait.php @@ -141,10 +141,6 @@ trait AppMockTrait ->shouldReceive('get') ->with('database', 'database') ->andReturn(getenv('MYSQL_DATABASE')); - $this->configMock - ->shouldReceive('get') - ->with('database', 'disable_pdo') - ->andReturn(true); $this->configMock ->shouldReceive('get') ->with('config', 'hostname') From 15b71edbd65e15a53e69f27ac58e300ea768c5df Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Nov 2020 07:29:13 +0000 Subject: [PATCH 17/17] Test database error --- tests/functional/DependencyCheckTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 8c1c5ac93e..da7103e43b 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -121,6 +121,11 @@ class DependencyCheckTest extends TestCase self::assertInstanceOf(Database::class, $database); self::assertContains($database->getDriver(), [Database::PDO, Database::MYSQLI], 'The driver returns an unexpected value'); self::assertNotNull($database->getConnection(), 'There is no database connection'); + + $result = $database->p("SELECT 1"); + self::assertEquals($database->errorMessage(), '', 'There had been a database error message'); + self::assertEquals($database->errorNo(), 0, 'There had been a database error number'); + self::assertTrue($database->connected(), 'The database is not connected'); }