Merge remote-tracking branch 'upstream/develop' into item-lock
This commit is contained in:
commit
930897046d
36 changed files with 918 additions and 106 deletions
2
.github/workflows/php.yml
vendored
2
.github/workflows/php.yml
vendored
|
@ -37,7 +37,7 @@ jobs:
|
|||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: pecl
|
||||
tools: pecl, composer:v1
|
||||
extensions: pdo_mysql, gd, zip, opcache, ctype, pcntl, ldap, apcu, memcached, redis, imagick, memcache
|
||||
coverage: xdebug
|
||||
ini-values: apc.enabled=1, apc.enable_cli=1
|
||||
|
|
26
database.sql
26
database.sql
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2020.12-dev (Red Hot Poker)
|
||||
-- DB_UPDATE_VERSION 1370
|
||||
-- DB_UPDATE_VERSION 1372
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -775,6 +775,7 @@ CREATE TABLE IF NOT EXISTS `item-content` (
|
|||
`title` varchar(255) NOT NULL DEFAULT '' COMMENT 'item title',
|
||||
`content-warning` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`body` mediumtext COMMENT 'item body content',
|
||||
`raw-body` mediumtext COMMENT 'Body without embedded media links',
|
||||
`location` varchar(255) NOT NULL DEFAULT '' COMMENT 'text location where this item originated',
|
||||
`coord` varchar(255) NOT NULL DEFAULT '' COMMENT 'longitude/latitude pair representing location where this item originated',
|
||||
`language` text COMMENT 'Language information about this post',
|
||||
|
@ -1064,6 +1065,27 @@ CREATE TABLE IF NOT EXISTS `post-delivery-data` (
|
|||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for items';
|
||||
|
||||
--
|
||||
-- TABLE post-media
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `post-media` (
|
||||
`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',
|
||||
`url` varbinary(511) NOT NULL COMMENT 'Media URL',
|
||||
`type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Media type',
|
||||
`mimetype` varchar(60) COMMENT '',
|
||||
`height` smallint unsigned COMMENT 'Height of the media',
|
||||
`width` smallint unsigned COMMENT 'Width of the media',
|
||||
`size` int unsigned COMMENT 'Media size',
|
||||
`preview` varbinary(255) COMMENT 'Preview URL',
|
||||
`preview-height` smallint unsigned COMMENT 'Height of the preview picture',
|
||||
`preview-width` smallint unsigned COMMENT 'Width of the preview picture',
|
||||
`description` text COMMENT '',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `uri-id-url` (`uri-id`,`url`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Attached media';
|
||||
|
||||
--
|
||||
-- TABLE post-tag
|
||||
--
|
||||
|
@ -1390,7 +1412,7 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
|
|||
PRIMARY KEY(`id`),
|
||||
INDEX `done_parameter` (`done`,`parameter`(64)),
|
||||
INDEX `done_executed` (`done`,`executed`),
|
||||
INDEX `done_priority_created` (`done`,`priority`,`created`),
|
||||
INDEX `done_priority_retrial_created` (`done`,`priority`,`retrial`,`created`),
|
||||
INDEX `done_priority_next_try` (`done`,`priority`,`next_try`),
|
||||
INDEX `done_pid_next_try` (`done`,`pid`,`next_try`),
|
||||
INDEX `done_pid_retrial` (`done`,`pid`,`retrial`),
|
||||
|
|
|
@ -182,7 +182,7 @@ By default, any (valid) email address is allowed in registrations.
|
|||
|
||||
#### Allow Users to set remote_self
|
||||
|
||||
If you enable the `Allow Users to set remote_self` users can select Atom feeds from their contact list being their *remote self* in the advanced contact settings.
|
||||
If you enable the `Allow Users to set remote_self` users can select Atom feeds from their contact list being their *remote self* in the contact settings.
|
||||
Which means that postings by the remote self are automatically reposted by Friendica in their names.
|
||||
|
||||
This feature can be used to let the user mirror e.g. blog postings into their Friendica postings.
|
||||
|
|
|
@ -172,7 +172,7 @@ Wildcards werden akzeptiert Standardmäßig sind alle gültigen Email-Adressen e
|
|||
|
||||
#### Nutzern erlauben das remote_self Flag zu setzen
|
||||
|
||||
Webb du die Option `Nutzern erlauben das remote_self Flag zu setzen` aktivierst, können alle Nutzer Atom Feeds in den erweiterten Einstellungen des Kontakts als "Entferntes Konto" markieren.
|
||||
Webb du die Option `Nutzern erlauben das remote_self Flag zu setzen` aktivierst, können alle Nutzer Atom Feeds in den Kontakteinstellungen als "Entferntes Konto" markieren.
|
||||
Dadurch werden automatisch alle Beiträge dieser Feeds für diesen Nutzer gespiegelt und an die Kontakte bei Friendica verteilt.
|
||||
|
||||
Dieses Feature kann z.B. dafür genutzt werden Blogbeiträge zu spiegeln.
|
||||
|
|
|
@ -292,7 +292,7 @@ class PageInfo
|
|||
$quotedUrl
|
||||
)$#isx", function ($match) use ($url) {
|
||||
// Stripping URLs with no label
|
||||
if (!isset($match[1])) {
|
||||
if (empty($match[1])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -146,13 +146,15 @@ class BBCode
|
|||
public static function getAttachmentData($body)
|
||||
{
|
||||
$data = [
|
||||
'type' => '',
|
||||
'text' => '',
|
||||
'after' => '',
|
||||
'image' => null,
|
||||
'url' => '',
|
||||
'title' => '',
|
||||
'description' => '',
|
||||
'type' => '',
|
||||
'text' => '',
|
||||
'after' => '',
|
||||
'image' => null,
|
||||
'url' => '',
|
||||
'provider_name' => '',
|
||||
'provider_url' => '',
|
||||
'title' => '',
|
||||
'description' => '',
|
||||
];
|
||||
|
||||
if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match)) {
|
||||
|
@ -253,6 +255,16 @@ class BBCode
|
|||
|
||||
$data['after'] = trim($match[4]);
|
||||
|
||||
$parts = parse_url($data['url']);
|
||||
if (!empty($parts['scheme']) && !empty($parts['host'])) {
|
||||
$data['provider_name'] = $parts['host'];
|
||||
$data['provider_url'] = $parts['scheme'] . '://' . $parts['host'];
|
||||
|
||||
if (!empty($parts['port'])) {
|
||||
$data['provider_url'] .= ':' . $parts['port'];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,7 @@ class Process
|
|||
public function run($command, $args)
|
||||
{
|
||||
if (!function_exists('proc_open')) {
|
||||
$this->logger->notice('"proc_open" not available - quitting');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -242,6 +243,7 @@ class Process
|
|||
}
|
||||
|
||||
if ($this->isMinMemoryReached()) {
|
||||
$this->logger->notice('Memory limit reached - quitting');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -251,9 +253,11 @@ class Process
|
|||
$resource = proc_open($cmdline . ' &', [], $foo, $this->basePath);
|
||||
}
|
||||
if (!is_resource($resource)) {
|
||||
$this->logger->debug('We got no resource for command.', ['cmd' => $cmdline]);
|
||||
$this->logger->notice('We got no resource for command.', ['command' => $cmdline]);
|
||||
return;
|
||||
}
|
||||
proc_close($resource);
|
||||
|
||||
$this->logger->info('Executed "proc_open"', ['command' => $cmdline, 'callstack' => System::callstack(10)]);
|
||||
}
|
||||
}
|
||||
|
|
16
src/DI.php
16
src/DI.php
|
@ -279,6 +279,22 @@ abstract class DI
|
|||
return self::$dice->create(Factory\Api\Mastodon\Status::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Mention
|
||||
*/
|
||||
public static function mstdnMention()
|
||||
{
|
||||
return self::$dice->create(Factory\Api\Mastodon\Mention::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Mastodon\Tag
|
||||
*/
|
||||
public static function mstdnTag()
|
||||
{
|
||||
return self::$dice->create(Factory\Api\Mastodon\Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Factory\Api\Twitter\User
|
||||
*/
|
||||
|
|
|
@ -69,7 +69,15 @@ class Account extends BaseFactory
|
|||
|
||||
$apcontact = APContact::getByURL($publicContact['url'], false);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Account($this->baseUrl, $publicContact, new Fields(), $apcontact, $userContact);
|
||||
$self_contact = Contact::selectFirst(['uid'], ['nurl' => $publicContact['nurl'], 'self' => true]);
|
||||
if (!empty($self_contact['uid'])) {
|
||||
$profileFields = $this->profileField->select(['uid' => $self_contact['uid'], 'psid' => PermissionSet::PUBLIC]);
|
||||
$fields = $this->mstdnField->createFromProfileFields($profileFields);
|
||||
} else {
|
||||
$fields = new Fields();
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Account($this->baseUrl, $publicContact, $fields, $apcontact, $userContact);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@ class Field extends BaseFactory
|
|||
*/
|
||||
public function createFromProfileField(ProfileField $profileField)
|
||||
{
|
||||
return new \Friendica\Api\Entity\Mastodon\Field($profileField->label, BBCode::convert($profileField->value, false, BBCode::ACTIVITYPUB));
|
||||
return new \Friendica\Object\Api\Mastodon\Field($profileField->label, BBCode::convert($profileField->value, false, BBCode::ACTIVITYPUB));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
67
src/Factory/Api/Mastodon/Mention.php
Normal file
67
src/Factory/Api/Mastodon/Mention.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Mention extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
{
|
||||
$mentions = [];
|
||||
$tags = Tag::getByURIId($uriId, [Tag::MENTION, Tag::EXCLUSIVE_MENTION, Tag::IMPLICIT_MENTION]);
|
||||
foreach ($tags as $tag) {
|
||||
$contact = Contact::getByURL($tag['url'], false);
|
||||
$mention = new \Friendica\Object\Api\Mastodon\Mention($this->baseUrl, $tag, $contact);
|
||||
$mentions[] = $mention->toArray();
|
||||
}
|
||||
return $mentions;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ namespace Friendica\Factory\Api\Mastodon;
|
|||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
|
@ -68,6 +69,22 @@ class Status extends BaseFactory
|
|||
DBA::count('item', ['thr-parent-id' => $uriId, 'uid' => $uid, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE)])
|
||||
);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts);
|
||||
$userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(
|
||||
DBA::exists('item', ['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE)]),
|
||||
DBA::exists('item', ['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE)]),
|
||||
DBA::exists('thread', ['iid' => $item['id'], 'uid' => $item['uid'], 'ignored' => true]),
|
||||
(bool)$item['starred'],
|
||||
DBA::exists('user-item', ['iid' => $item['id'], 'uid' => $item['uid'], 'pinned' => true])
|
||||
);
|
||||
|
||||
$sensitive = DBA::exists('tag-view', ['uri-id' => $uriId, 'name' => 'nsfw']);
|
||||
$application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?? '');
|
||||
$mentions = DI::mstdnMention()->createFromUriId($uriId);
|
||||
$tags = DI::mstdnTag()->createFromUriId($uriId);
|
||||
|
||||
$attachment = BBCode::getAttachmentData($item['body']);
|
||||
$card = new \Friendica\Object\Api\Mastodon\Card($attachment);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card);
|
||||
}
|
||||
}
|
||||
|
|
65
src/Factory/Api/Mastodon/Tag.php
Normal file
65
src/Factory/Api/Mastodon/Tag.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Model\Tag as TagModel;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Repository\ProfileField;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Tag extends BaseFactory
|
||||
{
|
||||
/** @var BaseURL */
|
||||
protected $baseUrl;
|
||||
/** @var ProfileField */
|
||||
protected $profileField;
|
||||
/** @var Field */
|
||||
protected $mstdnField;
|
||||
|
||||
public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileField $profileField, Field $mstdnField)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
|
||||
$this->baseUrl = $baseURL;
|
||||
$this->profileField = $profileField;
|
||||
$this->mstdnField = $mstdnField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public function createFromUriId(int $uriId)
|
||||
{
|
||||
$hashtags = [];
|
||||
$tags = TagModel::getByURIId($uriId, [TagModel::HASHTAG]);
|
||||
foreach ($tags as $tag) {
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag);
|
||||
$hashtags[] = $hashtag->toArray();
|
||||
}
|
||||
return $hashtags;
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@ class Item
|
|||
'object-type', 'object', 'target-type', 'target', 'plink'];
|
||||
|
||||
// Field list for "item-content" table that is not present in the "item" table
|
||||
const CONTENT_FIELDLIST = ['language'];
|
||||
const CONTENT_FIELDLIST = ['language', 'raw-body'];
|
||||
|
||||
// All fields in the item table
|
||||
const ITEM_FIELDLIST = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent',
|
||||
|
@ -1680,6 +1680,7 @@ class Item
|
|||
$item['deny_gid'] = trim($item['deny_gid'] ?? '');
|
||||
$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);
|
||||
|
@ -1818,6 +1819,10 @@ class Item
|
|||
self::setOwnerforResharedItem($item);
|
||||
}
|
||||
|
||||
// Remove all media attachments from the body and store them in the post-media table
|
||||
$item['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $item['raw-body']);
|
||||
$item['raw-body'] = self::setHashtags($item['raw-body']);
|
||||
|
||||
// Check for hashtags in the body and repair or add hashtag links
|
||||
$item['body'] = self::setHashtags($item['body']);
|
||||
|
||||
|
|
171
src/Model/Post/Media.php
Normal file
171
src/Model/Post/Media.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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 Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\Images;
|
||||
|
||||
/**
|
||||
* Class Media
|
||||
*
|
||||
* This Model class handles media interactions.
|
||||
* This tables stores medias (images, videos, audio files) related to posts.
|
||||
*/
|
||||
class Media
|
||||
{
|
||||
const UNKNOWN = 0;
|
||||
const IMAGE = 1;
|
||||
const VIDEO = 2;
|
||||
const AUDIO = 3;
|
||||
const TORRENT = 16;
|
||||
|
||||
/**
|
||||
* Insert a post-media record
|
||||
*
|
||||
* @param array $media
|
||||
* @return void
|
||||
*/
|
||||
public static function insert(array $media)
|
||||
{
|
||||
if (empty($media['url']) || empty($media['uri-id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DBA::exists('post-media', ['uri-id' => $media['uri-id'], 'url' => $media['url']])) {
|
||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = ['type', 'mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'description'];
|
||||
foreach ($fields as $field) {
|
||||
if (empty($media[$field])) {
|
||||
unset($media[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($media['type'] == self::IMAGE) {
|
||||
$imagedata = Images::getInfoFromURLCached($media['url']);
|
||||
if (!empty($imagedata)) {
|
||||
$media['mimetype'] = $imagedata['mime'];
|
||||
$media['size'] = $imagedata['size'];
|
||||
$media['width'] = $imagedata[0];
|
||||
$media['height'] = $imagedata[1];
|
||||
}
|
||||
if (!empty($media['preview'])) {
|
||||
$imagedata = Images::getInfoFromURLCached($media['preview']);
|
||||
if (!empty($imagedata)) {
|
||||
$media['preview-width'] = $imagedata[0];
|
||||
$media['preview-height'] = $imagedata[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = DBA::insert('post-media', $media, true);
|
||||
Logger::info('Stored media', ['result' => $result, 'media' => $media, 'callstack' => System::callstack()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for path patterns that are usef for picture links in Friendica
|
||||
*
|
||||
* @param string $page Link to the image page
|
||||
* @param string $preview Preview picture
|
||||
* @return boolean
|
||||
*/
|
||||
private static function isPictureLink(string $page, string $preview)
|
||||
{
|
||||
return preg_match('#/photos/.*/image/#ism', $page) && preg_match('#/photo/.*-1\.#ism', $preview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add media links and remove them from the body
|
||||
*
|
||||
* @param integer $uriid
|
||||
* @param string $body
|
||||
* @return string Body without media links
|
||||
*/
|
||||
public static function insertFromBody(int $uriid, string $body)
|
||||
{
|
||||
// Simplify image codes
|
||||
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
|
||||
|
||||
$attachments = [];
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (!self::isPictureLink($picture[1], $picture[2])) {
|
||||
continue;
|
||||
}
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$image = str_replace('-1.', '-0.', $picture[2]);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image,
|
||||
'preview' => $picture[2], 'description' => $picture[3]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $picture[1], 'description' => $picture[2]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (!self::isPictureLink($picture[1], $picture[2])) {
|
||||
continue;
|
||||
}
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$image = str_replace('-1.', '-0.', $picture[2]);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image,
|
||||
'preview' => $picture[2], 'description' => null];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $picture[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[audio\]([^\[\]]*)\[\/audio\]/ism", $body, $audios, PREG_SET_ORDER)) {
|
||||
foreach ($audios as $audio) {
|
||||
$body = str_replace($audio[0], '', $body);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::AUDIO, 'url' => $audio[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[video\]([^\[\]]*)\[\/video\]/ism", $body, $videos, PREG_SET_ORDER)) {
|
||||
foreach ($videos as $video) {
|
||||
$body = str_replace($video[0], '', $body);
|
||||
$attachments[] = ['uri-id' => $uriid, 'type' => self::VIDEO, 'url' => $video[1]];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
self::insert($attachment);
|
||||
}
|
||||
|
||||
return trim($body);
|
||||
}
|
||||
}
|
|
@ -417,7 +417,11 @@ class Site extends BaseAdmin
|
|||
DI::config()->set('system', 'only_tag_search' , $only_tag_search);
|
||||
|
||||
DI::config()->set('system', 'worker_queues' , $worker_queues);
|
||||
DI::config()->set('system', 'worker_dont_fork' , $worker_dont_fork);
|
||||
|
||||
if (function_exists('proc_open')) {
|
||||
DI::config()->set('system', 'worker_dont_fork', $worker_dont_fork);
|
||||
}
|
||||
|
||||
DI::config()->set('system', 'worker_fastlane' , $worker_fastlane);
|
||||
DI::config()->set('system', 'frontend_worker' , $worker_frontend);
|
||||
|
||||
|
@ -578,6 +582,14 @@ class Site extends BaseAdmin
|
|||
}
|
||||
}
|
||||
|
||||
if (function_exists('proc_open')) {
|
||||
$worker_dont_fork = DI::config()->get('system', 'worker_dont_fork');
|
||||
$worker_dont_fork_disabled = '';
|
||||
} else {
|
||||
$worker_dont_fork = true;
|
||||
$worker_dont_fork_disabled = 'disabled';
|
||||
}
|
||||
|
||||
$t = Renderer::getMarkupTemplate('admin/site.tpl');
|
||||
return Renderer::replaceMacros($t, [
|
||||
'$title' => DI::l10n()->t('Administration'),
|
||||
|
@ -689,7 +701,7 @@ class Site extends BaseAdmin
|
|||
'$rino' => ['rino', DI::l10n()->t('RINO Encryption'), intval(DI::config()->get('system', 'rino_encrypt')), DI::l10n()->t('Encryption layer between nodes.'), [0 => DI::l10n()->t('Disabled'), 1 => DI::l10n()->t('Enabled')]],
|
||||
|
||||
'$worker_queues' => ['worker_queues', DI::l10n()->t('Maximum number of parallel workers'), DI::config()->get('system', 'worker_queues'), DI::l10n()->t('On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.', 5, 20, 10)],
|
||||
'$worker_dont_fork' => ['worker_dont_fork', DI::l10n()->t('Don\'t use "proc_open" with the worker'), DI::config()->get('system', 'worker_dont_fork'), DI::l10n()->t('Enable this if your system doesn\'t allow the use of "proc_open". This can happen on shared hosters. If this is enabled you should increase the frequency of worker calls in your crontab.')],
|
||||
'$worker_dont_fork' => ['worker_dont_fork', DI::l10n()->t('Don\'t use "proc_open" with the worker'), $worker_dont_fork, DI::l10n()->t('Enable this if your system doesn\'t allow the use of "proc_open". This can happen on shared hosters. If this is enabled you should increase the frequency of worker calls in your crontab.'), $worker_dont_fork_disabled],
|
||||
'$worker_fastlane' => ['worker_fastlane', DI::l10n()->t('Enable fastlane'), DI::config()->get('system', 'worker_fastlane'), DI::l10n()->t('When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.')],
|
||||
'$worker_frontend' => ['worker_frontend', DI::l10n()->t('Enable frontend worker'), DI::config()->get('system', 'frontend_worker'), DI::l10n()->t('When enabled the Worker process is triggered when backend access is performed (e.g. messages being delivered). On smaller sites you might want to call %s/worker on a regular basis via an external cron job. You should only enable this option if you cannot utilize cron/scheduled jobs on your server.', DI::baseUrl()->get())],
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Content\ContactSelector;
|
||||
use Friendica\Content\Nav;
|
||||
|
@ -132,6 +131,8 @@ class Contact extends BaseModule
|
|||
|
||||
$fetch_further_information = intval($_POST['fetch_further_information'] ?? 0);
|
||||
|
||||
$remote_self = $_POST['remote_self'] ?? false;
|
||||
|
||||
$ffi_keyword_denylist = Strings::escapeHtml(trim($_POST['ffi_keyword_denylist'] ?? ''));
|
||||
|
||||
$priority = intval($_POST['poll'] ?? 0);
|
||||
|
@ -147,6 +148,7 @@ class Contact extends BaseModule
|
|||
'hidden' => $hidden,
|
||||
'notify_new_posts' => $notify,
|
||||
'fetch_further_information' => $fetch_further_information,
|
||||
'remote_self' => $remote_self,
|
||||
'ffi_keyword_denylist' => $ffi_keyword_denylist],
|
||||
['id' => $contact_id, 'uid' => local_user()]
|
||||
);
|
||||
|
@ -555,6 +557,18 @@ class Contact extends BaseModule
|
|||
];
|
||||
}
|
||||
|
||||
// Disable remote self for everything except feeds.
|
||||
// There is an issue when you repeat an item from maybe twitter and you got comments from friendica and twitter
|
||||
// Problem is, you couldn't reply to both networks.
|
||||
$allow_remote_self = in_array($contact['network'], [Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
|
||||
&& DI::config()->get('system', 'allow_users_remote_self');
|
||||
|
||||
if ($contact['network'] == Protocol::FEED) {
|
||||
$remote_self_options = ['0' => DI::l10n()->t('No mirroring'), '1' => DI::l10n()->t('Mirror as forwarded posting'), '2' => DI::l10n()->t('Mirror as my own posting')];
|
||||
} else {
|
||||
$remote_self_options = ['0' => DI::l10n()->t('No mirroring'), '2' => DI::l10n()->t('Mirror as my own posting')];
|
||||
}
|
||||
|
||||
$poll_interval = null;
|
||||
if ((($contact['network'] == Protocol::FEED) && !DI::config()->get('system', 'adjust_poll_frequency')) || ($contact['network']== Protocol::MAIL)) {
|
||||
$poll_interval = ContactSelector::pollInterval($contact['priority'], !$poll_enabled);
|
||||
|
@ -629,6 +643,13 @@ class Contact extends BaseModule
|
|||
'$contact_status' => DI::l10n()->t('Status'),
|
||||
'$contact_settings_label' => $contact_settings_label,
|
||||
'$contact_profile_label' => DI::l10n()->t('Profile'),
|
||||
'$allow_remote_self' => $allow_remote_self,
|
||||
'$remote_self' => ['remote_self',
|
||||
DI::l10n()->t('Mirror postings from this contact'),
|
||||
$contact['remote_self'],
|
||||
DI::l10n()->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
|
||||
$remote_self_options
|
||||
],
|
||||
]);
|
||||
|
||||
$arr = ['contact' => $contact, 'output' => $o];
|
||||
|
@ -916,7 +937,7 @@ class Contact extends BaseModule
|
|||
],
|
||||
];
|
||||
|
||||
if ($cid != $pcid) {
|
||||
if (!empty($contact['network']) && in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) && ($cid != $pcid)) {
|
||||
$tabs[] = ['label' => DI::l10n()->t('Advanced'),
|
||||
'url' => 'contact/' . $cid . '/advanced/',
|
||||
'sel' => (($active_tab == self::TAB_ADVANCED) ? 'active' : ''),
|
||||
|
|
|
@ -63,7 +63,6 @@ class Advanced extends BaseModule
|
|||
$poll = $_POST['poll'] ?? '';
|
||||
$attag = $_POST['attag'] ?? '';
|
||||
$photo = $_POST['photo'] ?? '';
|
||||
$remote_self = $_POST['remote_self'] ?? false;
|
||||
$nurl = Strings::normaliseLink($url);
|
||||
|
||||
$r = DI::dba()->update(
|
||||
|
@ -79,7 +78,6 @@ class Advanced extends BaseModule
|
|||
'notify' => $notify,
|
||||
'poll' => $poll,
|
||||
'attag' => $attag,
|
||||
'remote_self' => $remote_self,
|
||||
],
|
||||
['id' => $contact['id'], 'uid' => local_user()]
|
||||
);
|
||||
|
@ -113,18 +111,6 @@ class Advanced extends BaseModule
|
|||
|
||||
$returnaddr = "contact/$cid";
|
||||
|
||||
// Disable remote self for everything except feeds.
|
||||
// There is an issue when you repeat an item from maybe twitter and you got comments from friendica and twitter
|
||||
// Problem is, you couldn't reply to both networks.
|
||||
$allow_remote_self = in_array($contact['network'], [Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
|
||||
&& DI::config()->get('system', 'allow_users_remote_self');
|
||||
|
||||
if ($contact['network'] == Protocol::FEED) {
|
||||
$remote_self_options = ['0' => DI::l10n()->t('No mirroring'), '1' => DI::l10n()->t('Mirror as forwarded posting'), '2' => DI::l10n()->t('Mirror as my own posting')];
|
||||
} else {
|
||||
$remote_self_options = ['0' => DI::l10n()->t('No mirroring'), '2' => DI::l10n()->t('Mirror as my own posting')];
|
||||
}
|
||||
|
||||
// This data is fetched automatically for most networks.
|
||||
// Editing does only makes sense for mail and feed contacts.
|
||||
if (!in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
|
||||
|
@ -146,14 +132,6 @@ class Advanced extends BaseModule
|
|||
'$udprofilenow' => DI::l10n()->t('Refetch contact data'),
|
||||
'$contact_id' => $contact['id'],
|
||||
'$lbl_submit' => DI::l10n()->t('Submit'),
|
||||
'$label_remote_self' => DI::l10n()->t('Remote Self'),
|
||||
'$allow_remote_self' => $allow_remote_self,
|
||||
'$remote_self' => ['remote_self',
|
||||
DI::l10n()->t('Mirror postings from this contact'),
|
||||
$contact['remote_self'],
|
||||
DI::l10n()->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
|
||||
$remote_self_options
|
||||
],
|
||||
|
||||
'$name' => ['name', DI::l10n()->t('Name'), $contact['name'], '', '', $readonly],
|
||||
'$nick' => ['nick', DI::l10n()->t('Account Nickname'), $contact['nick'], '', '', $readonly],
|
||||
|
|
|
@ -283,30 +283,32 @@ class Network extends BaseModule
|
|||
|
||||
self::$forumContactId = $parameters['contact_id'] ?? 0;
|
||||
|
||||
self::$selectedTab = Session::get('network-tab', '');
|
||||
self::$selectedTab = Session::get('network-tab', DI::pConfig()->get(local_user(), 'network.view', 'selected_tab', ''));
|
||||
|
||||
self::$order = 'commented';
|
||||
|
||||
if (!empty($get['star'])) {
|
||||
self::$selectedTab = 'star';
|
||||
self::$order = 'received';
|
||||
}
|
||||
|
||||
if (!empty($get['mention'])) {
|
||||
self::$selectedTab = 'mention';
|
||||
self::$order = 'received';
|
||||
}
|
||||
|
||||
if (!empty($get['order'])) {
|
||||
self::$selectedTab = $get['order'];
|
||||
self::$order = $get['order'];
|
||||
}
|
||||
|
||||
Session::set('network-tab', self::$selectedTab);
|
||||
|
||||
self::$star = intval($get['star'] ?? 0);
|
||||
self::$mention = intval($get['mention'] ?? 0);
|
||||
self::$order = $get['order'] ?? Session::get('network-order', 'commented');
|
||||
|
||||
self::$selectedTab = self::$selectedTab ?? self::$order;
|
||||
|
||||
Session::set('network-tab', self::$selectedTab);
|
||||
Session::set('network-order', self::$order);
|
||||
DI::pConfig()->set(local_user(), 'network.view', 'selected_tab', self::$selectedTab);
|
||||
|
||||
self::$accountTypeString = $get['accounttype'] ?? $parameters['accounttype'] ?? '';
|
||||
self::$accountType = User::getAccountTypeByString(self::$accountTypeString);
|
||||
|
@ -331,15 +333,15 @@ class Network extends BaseModule
|
|||
case 'received':
|
||||
self::$max_id = $get['last_received'] ?? self::$max_id;
|
||||
break;
|
||||
case 'commented':
|
||||
self::$max_id = $get['last_commented'] ?? self::$max_id;
|
||||
break;
|
||||
case 'created':
|
||||
self::$max_id = $get['last_created'] ?? self::$max_id;
|
||||
break;
|
||||
case 'uriid':
|
||||
self::$max_id = $get['last_uriid'] ?? self::$max_id;
|
||||
break;
|
||||
default:
|
||||
self::$order = 'commented';
|
||||
self::$max_id = $get['last_commented'] ?? self::$max_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ class Account extends BaseEntity
|
|||
$publicContact['nick'] :
|
||||
$publicContact['addr'];
|
||||
$this->display_name = $publicContact['name'];
|
||||
$this->locked = $publicContact['manually-approve'] ?? !empty($apcontact['manually-approve']);
|
||||
$this->locked = (bool)$publicContact['manually-approve'] ?? !empty($apcontact['manually-approve']);
|
||||
$this->bot = ($publicContact['contact-type'] == Contact::TYPE_NEWS);
|
||||
$this->discoverable = !$publicContact['unsearchable'];
|
||||
$this->group = ($publicContact['contact-type'] == Contact::TYPE_COMMUNITY);
|
||||
|
@ -132,4 +132,20 @@ class Account extends BaseEntity
|
|||
$this->fields = $fields->getArrayCopy();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current entity as an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$account = parent::toArray();
|
||||
|
||||
if (empty($account['moved'])) {
|
||||
unset($account['moved']);
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
|
|
78
src/Object/Api/Mastodon/Card.php
Normal file
78
src/Object/Api/Mastodon/Card.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Object\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseEntity;
|
||||
|
||||
/**
|
||||
* Class Card
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/entities/card
|
||||
*/
|
||||
class Card extends BaseEntity
|
||||
{
|
||||
/** @var string */
|
||||
protected $url;
|
||||
/** @var string */
|
||||
protected $title;
|
||||
/** @var string */
|
||||
protected $description;
|
||||
/** @var string */
|
||||
protected $type;
|
||||
/** @var string */
|
||||
protected $provider_name;
|
||||
/** @var string */
|
||||
protected $provider_url;
|
||||
/** @var string */
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* Creates a card record from an attachment array.
|
||||
*
|
||||
* @param array $attachment Attachment record
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(array $attachment)
|
||||
{
|
||||
$this->url = $attachment['url'] ?? '';
|
||||
$this->title = $attachment['title'] ?? '';
|
||||
$this->description = $attachment['description'] ?? '';
|
||||
$this->type = $attachment['type'] ?? '';
|
||||
$this->image = $attachment['image'] ?? '';
|
||||
$this->provider_name = $attachment['provider_name'] ?? '';
|
||||
$this->provider_url = $attachment['provider_url'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current entity as an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
if (empty($this->url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parent::toArray();
|
||||
}
|
||||
}
|
66
src/Object/Api/Mastodon/Mention.php
Normal file
66
src/Object/Api/Mastodon/Mention.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Object\Api\Mastodon;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseEntity;
|
||||
|
||||
/**
|
||||
* Class Mention
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/entities/mention
|
||||
*/
|
||||
class Mention extends BaseEntity
|
||||
{
|
||||
/** @var string */
|
||||
protected $id;
|
||||
/** @var string */
|
||||
protected $username;
|
||||
/** @var string */
|
||||
protected $url = null;
|
||||
/** @var string */
|
||||
protected $acct = null;
|
||||
|
||||
/**
|
||||
* Creates a mention record from an tag-view record.
|
||||
*
|
||||
* @param BaseURL $baseUrl
|
||||
* @param array $tag tag-view record
|
||||
* @param array $contact contact table record
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(BaseURL $baseUrl, array $tag, array $contact)
|
||||
{
|
||||
$this->id = $contact['id'] ?? 0;
|
||||
$this->username = $tag['name'];
|
||||
$this->url = $tag['url'];
|
||||
|
||||
if (!empty($contact)) {
|
||||
$this->acct =
|
||||
strpos($contact['url'], $baseUrl->get() . '/') === 0 ?
|
||||
$contact['nick'] :
|
||||
$contact['addr'];
|
||||
} else {
|
||||
$this->acct = '';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ namespace Friendica\Object\Api\Mastodon;
|
|||
use Friendica\BaseEntity;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Object\Api\Mastodon\Status\Counts;
|
||||
use Friendica\Object\Api\Mastodon\Status\UserAttributes;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
|
@ -96,7 +97,7 @@ class Status extends BaseEntity
|
|||
* @param array $item
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(array $item, Account $account, Counts $counts)
|
||||
public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card)
|
||||
{
|
||||
$this->id = (string)$item['uri-id'];
|
||||
$this->created_at = DateTimeFormat::utc($item['created'], DateTimeFormat::ATOM);
|
||||
|
@ -106,32 +107,54 @@ class Status extends BaseEntity
|
|||
$this->in_reply_to_account_id = (string)$item['parent-author-id'];
|
||||
}
|
||||
|
||||
$this->sensitive = false;
|
||||
$this->sensitive = $sensitive;
|
||||
$this->spoiler_text = $item['title'];
|
||||
|
||||
$visibility = ['public', 'private', 'unlisted'];
|
||||
$this->visibility = $visibility[$item['private']];
|
||||
|
||||
$this->language = null;
|
||||
$languages = json_decode($item['language'], true);
|
||||
$this->language = is_array($languages) ? array_key_first($languages) : null;
|
||||
|
||||
$this->uri = $item['uri'];
|
||||
$this->url = $item['plink'] ?? null;
|
||||
$this->replies_count = $counts->replies;
|
||||
$this->reblogs_count = $counts->reblogs;
|
||||
$this->favourites_count = $counts->favourites;
|
||||
$this->favourited = false;
|
||||
$this->reblogged = false;
|
||||
$this->muted = false;
|
||||
$this->bookmarked = false;
|
||||
$this->pinned = false;
|
||||
$this->favourited = $userAttributes->favourited;
|
||||
$this->reblogged = $userAttributes->reblogged;
|
||||
$this->muted = $userAttributes->muted;
|
||||
$this->bookmarked = $userAttributes->bookmarked;
|
||||
$this->pinned = $userAttributes->pinned;
|
||||
$this->content = BBCode::convert($item['body'], false);
|
||||
$this->reblog = null;
|
||||
$this->application = null;
|
||||
$this->reblog = null; /// @todo
|
||||
$this->application = $application->toArray();
|
||||
$this->account = $account->toArray();
|
||||
$this->media_attachments = [];
|
||||
$this->mentions = [];
|
||||
$this->tags = [];
|
||||
$this->media_attachments = []; /// @todo
|
||||
$this->mentions = $mentions;
|
||||
$this->tags = $tags;
|
||||
$this->emojis = [];
|
||||
$this->card = null;
|
||||
$this->card = $card->toArray();
|
||||
$this->poll = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current entity as an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$status = parent::toArray();
|
||||
|
||||
if (!$status['pinned']) {
|
||||
unset($status['pinned']);
|
||||
}
|
||||
|
||||
if (empty($status['application']['name'])) {
|
||||
unset($status['application']);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,6 @@ class Counts
|
|||
}
|
||||
|
||||
public function __get($name) {
|
||||
return $this->$name;
|
||||
}
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
|
|
64
src/Object/Api/Mastodon/Status/UserAttributes.php
Normal file
64
src/Object/Api/Mastodon/Status/UserAttributes.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Object\Api\Mastodon\Status;
|
||||
|
||||
/**
|
||||
* Class UserAttributes
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/entities/status
|
||||
*/
|
||||
class UserAttributes
|
||||
{
|
||||
/** @var bool */
|
||||
protected $favourited;
|
||||
/** @var bool */
|
||||
protected $reblogged;
|
||||
/** @var bool */
|
||||
protected $muted;
|
||||
/** @var bool */
|
||||
protected $bookmarked;
|
||||
/** @var bool */
|
||||
protected $pinned;
|
||||
|
||||
/**
|
||||
* Creates a authorized user attributes object
|
||||
*
|
||||
* @param bool $favourited
|
||||
* @param bool $reblogged
|
||||
* @param bool $muted
|
||||
* @param bool $bookmarked
|
||||
* @param bool $pinned
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(bool $favourited, bool $reblogged, bool $muted, bool $bookmarked, bool $pinned)
|
||||
{
|
||||
$this->favourited = $favourited;
|
||||
$this->reblogged = $reblogged;
|
||||
$this->muted = $muted;
|
||||
$this->bookmarked = $bookmarked;
|
||||
$this->pinned = $pinned;
|
||||
}
|
||||
|
||||
public function __get($name) {
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
51
src/Object/Api/Mastodon/Tag.php
Normal file
51
src/Object/Api/Mastodon/Tag.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @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\Object\Api\Mastodon;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseEntity;
|
||||
|
||||
/**
|
||||
* Class Tag
|
||||
*
|
||||
* @see https://docs.joinmastodon.org/entities/tag
|
||||
*/
|
||||
class Tag extends BaseEntity
|
||||
{
|
||||
/** @var string */
|
||||
protected $name;
|
||||
/** @var string */
|
||||
protected $url = null;
|
||||
|
||||
/**
|
||||
* Creates a hashtag record from an tag-view record.
|
||||
*
|
||||
* @param BaseURL $baseUrl
|
||||
* @param array $tag tag-view record
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(BaseURL $baseUrl, array $tag)
|
||||
{
|
||||
$this->name = strtolower($tag['name']);
|
||||
$this->url = $baseUrl . '/search?tag=' . urlencode($this->name);
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ use Friendica\Model\ItemURI;
|
|||
use Friendica\Model\Mail;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Protocol\Relay;
|
||||
|
@ -81,6 +82,45 @@ class Processor
|
|||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store attached media files in the post-media table
|
||||
*
|
||||
* @param int $uriid
|
||||
* @param array $attachment
|
||||
* @return void
|
||||
*/
|
||||
private static function storeAttachmentAsMedia(int $uriid, array $attachment)
|
||||
{
|
||||
if (empty($attachment['url'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = ['uri-id' => $uriid];
|
||||
|
||||
$filetype = strtolower(substr($attachment['mediaType'], 0, strpos($attachment['mediaType'], '/')));
|
||||
if ($filetype == 'image') {
|
||||
$data['type'] = Post\Media::IMAGE;
|
||||
} elseif ($filetype == 'video') {
|
||||
$data['type'] = Post\Media::VIDEO;
|
||||
} elseif ($filetype == 'audio') {
|
||||
$data['type'] = Post\Media::AUDIO;
|
||||
} elseif (in_array($attachment['mediaType'], ['application/x-bittorrent', 'application/x-bittorrent;x-scheme-handler/magnet'])) {
|
||||
$data['type'] = Post\Media::TORRENT;
|
||||
} else {
|
||||
Logger::info('Unknown type', ['attachment' => $attachment]);
|
||||
return;
|
||||
}
|
||||
|
||||
$data['url'] = $attachment['url'];
|
||||
$data['mimetype'] = $attachment['mediaType'];
|
||||
$data['height'] = $attachment['height'] ?? null;
|
||||
$data['size'] = $attachment['size'] ?? null;
|
||||
$data['preview'] = $attachment['image'] ?? null;
|
||||
$data['description'] = $attachment['name'] ?? null;
|
||||
|
||||
Post\Media::insert($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add attachment data to the item array
|
||||
*
|
||||
|
@ -95,6 +135,8 @@ class Processor
|
|||
return $item;
|
||||
}
|
||||
|
||||
$item['attach'] = '';
|
||||
|
||||
foreach ($activity['attachments'] as $attach) {
|
||||
switch ($attach['type']) {
|
||||
case 'link':
|
||||
|
@ -110,6 +152,8 @@ class Processor
|
|||
$item['body'] = PageInfo::appendDataToBody($item['body'], $data);
|
||||
break;
|
||||
default:
|
||||
self::storeAttachmentAsMedia($item['uri-id'], $attach);
|
||||
|
||||
$filetype = strtolower(substr($attach['mediaType'], 0, strpos($attach['mediaType'], '/')));
|
||||
if ($filetype == 'image') {
|
||||
if (!empty($activity['source']) && strpos($activity['source'], $attach['url'])) {
|
||||
|
@ -146,13 +190,13 @@ class Processor
|
|||
|
||||
$item['body'] .= "\n[video]" . $attach['url'] . '[/video]';
|
||||
} else {
|
||||
if (!empty($item["attach"])) {
|
||||
$item["attach"] .= ',';
|
||||
if (!empty($item['attach'])) {
|
||||
$item['attach'] .= ',';
|
||||
} else {
|
||||
$item["attach"] = '';
|
||||
$item['attach'] = '';
|
||||
}
|
||||
|
||||
$item["attach"] .= '[attach]href="' . $attach['url'] . '" length="' . ($attach['length'] ?? '0') . '" type="' . $attach['mediaType'] . '" title="' . ($attach['name'] ?? '') . '"[/attach]';
|
||||
$item['attach'] .= '[attach]href="' . $attach['url'] . '" length="' . ($attach['length'] ?? '0') . '" type="' . $attach['mediaType'] . '" title="' . ($attach['name'] ?? '') . '"[/attach]';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +224,9 @@ class Processor
|
|||
$item['edited'] = DateTimeFormat::utc($activity['updated']);
|
||||
|
||||
$item = self::processContent($activity, $item);
|
||||
|
||||
$item = self::constructAttachList($activity, $item);
|
||||
|
||||
if (empty($item)) {
|
||||
return;
|
||||
}
|
||||
|
@ -403,17 +450,18 @@ class Processor
|
|||
{
|
||||
$item['title'] = HTML::toBBCode($activity['name']);
|
||||
|
||||
$content = HTML::toBBCode($activity['content']);
|
||||
|
||||
if (!empty($activity['emojis'])) {
|
||||
$content = self::replaceEmojis($content, $activity['emojis']);
|
||||
}
|
||||
|
||||
$content = self::convertMentions($content);
|
||||
|
||||
if (!empty($activity['source'])) {
|
||||
$item['body'] = $activity['source'];
|
||||
$item['raw-body'] = $content;
|
||||
} else {
|
||||
$content = HTML::toBBCode($activity['content']);
|
||||
|
||||
if (!empty($activity['emojis'])) {
|
||||
$content = self::replaceEmojis($content, $activity['emojis']);
|
||||
}
|
||||
|
||||
$content = self::convertMentions($content);
|
||||
|
||||
if (empty($activity['directmessage']) && ($item['thr-parent'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) {
|
||||
$item_private = !in_array(0, $activity['item_receiver']);
|
||||
$parent = Item::selectFirst(['id', 'uri-id', 'private', 'author-link', 'alias'], ['uri' => $item['thr-parent']]);
|
||||
|
@ -429,7 +477,7 @@ class Processor
|
|||
$content = self::removeImplicitMentionsFromBody($content, $parent);
|
||||
}
|
||||
$item['content-warning'] = HTML::toBBCode($activity['summary']);
|
||||
$item['body'] = $content;
|
||||
$item['raw-body'] = $item['body'] = $content;
|
||||
}
|
||||
|
||||
self::storeFromBody($item);
|
||||
|
|
|
@ -1231,24 +1231,36 @@ class Receiver
|
|||
$filetype = strtolower(substr($mediatype, 0, strpos($mediatype, '/')));
|
||||
|
||||
if ($filetype == 'audio') {
|
||||
$attachments[$filetype] = ['type' => $mediatype, 'url' => $href];
|
||||
$attachments[$filetype] = ['type' => $mediatype, 'url' => $href, 'height' => null, 'size' => null];
|
||||
} elseif ($filetype == 'video') {
|
||||
$height = (int)JsonLD::fetchElement($url, 'as:height', '@value');
|
||||
$size = (int)JsonLD::fetchElement($url, 'pt:size', '@value');
|
||||
|
||||
// We save bandwidth by using a moderate height
|
||||
// We save bandwidth by using a moderate height (alt least 480 pixel height)
|
||||
// Peertube normally uses these heights: 240, 360, 480, 720, 1080
|
||||
if (!empty($attachments[$filetype]['height']) &&
|
||||
(($height > 480) || $height < $attachments[$filetype]['height'])) {
|
||||
($height > $attachments[$filetype]['height']) && ($attachments[$filetype]['height'] >= 480)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachments[$filetype] = ['type' => $mediatype, 'url' => $href, 'height' => $height];
|
||||
$attachments[$filetype] = ['type' => $mediatype, 'url' => $href, 'height' => $height, 'size' => $size];
|
||||
} elseif (in_array($mediatype, ['application/x-bittorrent', 'application/x-bittorrent;x-scheme-handler/magnet'])) {
|
||||
$height = (int)JsonLD::fetchElement($url, 'as:height', '@value');
|
||||
|
||||
// For Torrent links we always store the highest resolution
|
||||
if (!empty($attachments[$mediatype]['height']) && ($height < $attachments[$mediatype]['height'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachments[$mediatype] = ['type' => $mediatype, 'url' => $href, 'height' => $height, 'size' => null];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachments as $type => $attachment) {
|
||||
$object_data['attachments'][] = ['type' => $type,
|
||||
'mediaType' => $attachment['type'],
|
||||
'height' => $attachment['height'],
|
||||
'size' => $attachment['size'],
|
||||
'name' => '',
|
||||
'url' => $attachment['url']];
|
||||
}
|
||||
|
|
|
@ -2810,6 +2810,26 @@ class Diaspora
|
|||
return Relay::isSolicitedPost($tags, $body, $contact['id'], $url, Protocol::DIASPORA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an attached photo in the post-media table
|
||||
*
|
||||
* @param int $uriid
|
||||
* @param object $photo
|
||||
* @return void
|
||||
*/
|
||||
private static function storePhotoAsMedia(int $uriid, $photo)
|
||||
{
|
||||
$data = [];
|
||||
$data['uri-id'] = $uriid;
|
||||
$data['type'] = Post\Media::IMAGE;
|
||||
$data['url'] = XML::unescape($photo->remote_photo_path) . XML::unescape($photo->remote_photo_name);
|
||||
$data['height'] = (int)XML::unescape($photo->height ?? 0);
|
||||
$data['width'] = (int)XML::unescape($photo->width ?? 0);
|
||||
$data['description'] = XML::unescape($photo->text ?? '');
|
||||
|
||||
Post\Media::insert($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives status messages
|
||||
*
|
||||
|
@ -2847,13 +2867,18 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$body = Markdown::toBBCode($text);
|
||||
$raw_body = $body = Markdown::toBBCode($text);
|
||||
|
||||
$datarray = [];
|
||||
|
||||
$datarray["guid"] = $guid;
|
||||
$datarray["uri"] = $datarray["parent-uri"] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
// Attach embedded pictures to the body
|
||||
if ($data->photo) {
|
||||
foreach ($data->photo as $photo) {
|
||||
self::storePhotoAsMedia($datarray['uri-id'], $photo);
|
||||
$body = "[img]".XML::unescape($photo->remote_photo_path).
|
||||
XML::unescape($photo->remote_photo_name)."[/img]\n".$body;
|
||||
}
|
||||
|
@ -2887,10 +2912,6 @@ class Diaspora
|
|||
$datarray["owner-link"] = $datarray["author-link"];
|
||||
$datarray["owner-id"] = $datarray["author-id"];
|
||||
|
||||
$datarray["guid"] = $guid;
|
||||
$datarray["uri"] = $datarray["parent-uri"] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
$datarray["verb"] = Activity::POST;
|
||||
$datarray["gravity"] = GRAVITY_PARENT;
|
||||
|
||||
|
@ -2904,6 +2925,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
$datarray["body"] = self::replacePeopleGuid($body, $contact["url"]);
|
||||
$datarray["raw-body"] = self::replacePeopleGuid($raw_body, $contact["url"]);
|
||||
|
||||
self::storeMentions($datarray['uri-id'], $text);
|
||||
Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray["body"]);
|
||||
|
|
|
@ -31,9 +31,19 @@ class CleanItemUri
|
|||
*/
|
||||
public static function execute()
|
||||
{
|
||||
$ret = DBA::e("DELETE FROM `item-uri` WHERE NOT `id` IN (SELECT `uri-id` FROM `item`)
|
||||
// We have to avoid deleting newly created "item-uri" entries.
|
||||
// So we fetch a post that had been stored yesterday and only delete older ones.
|
||||
$item = DBA::selectFirst('item', ['uri-id'], ["`uid` = ? AND `received` < UTC_TIMESTAMP() - INTERVAL ? DAY", 0, 1],
|
||||
['order' => ['received' => true]]);
|
||||
if (empty($item['uri-id'])) {
|
||||
Logger::warning('No item with uri-id found - we better quit here');
|
||||
return;
|
||||
}
|
||||
Logger::notice('Start deleting orphaned URI-ID', ['last-id' => $item['uri-id']]);
|
||||
$ret = DBA::e("DELETE FROM `item-uri` WHERE `id` < ?
|
||||
AND NOT `id` IN (SELECT `uri-id` FROM `item`)
|
||||
AND NOT `id` IN (SELECT `parent-uri-id` FROM `item`)
|
||||
AND NOT `id` IN (SELECT `thr-parent-id` FROM `item`)");
|
||||
AND NOT `id` IN (SELECT `thr-parent-id` FROM `item`)", $item['uri-id']);
|
||||
Logger::notice('Orphaned URI-ID entries removed', ['result' => $ret, 'rows' => DBA::affectedRows()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
use Friendica\Database\DBA;
|
||||
|
||||
if (!defined('DB_UPDATE_VERSION')) {
|
||||
define('DB_UPDATE_VERSION', 1371);
|
||||
define('DB_UPDATE_VERSION', 1372);
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -843,6 +843,7 @@ return [
|
|||
"title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "item title"],
|
||||
"content-warning" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"body" => ["type" => "mediumtext", "comment" => "item body content"],
|
||||
"raw-body" => ["type" => "mediumtext", "comment" => "Body without embedded media links"],
|
||||
"location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "text location where this item originated"],
|
||||
"coord" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "longitude/latitude pair representing location where this item originated"],
|
||||
"language" => ["type" => "text", "comment" => "Language information about this post"],
|
||||
|
@ -1133,6 +1134,27 @@ return [
|
|||
"PRIMARY" => ["uri-id"],
|
||||
]
|
||||
],
|
||||
"post-media" => [
|
||||
"comment" => "Attached media",
|
||||
"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"],
|
||||
"url" => ["type" => "varbinary(511)", "not null" => "1", "comment" => "Media URL"],
|
||||
"type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Media type"],
|
||||
"mimetype" => ["type" => "varchar(60)", "comment" => ""],
|
||||
"height" => ["type" => "smallint unsigned", "comment" => "Height of the media"],
|
||||
"width" => ["type" => "smallint unsigned", "comment" => "Width of the media"],
|
||||
"size" => ["type" => "int unsigned", "comment" => "Media size"],
|
||||
"preview" => ["type" => "varbinary(255)", "comment" => "Preview URL"],
|
||||
"preview-height" => ["type" => "smallint unsigned", "comment" => "Height of the preview picture"],
|
||||
"preview-width" => ["type" => "smallint unsigned", "comment" => "Width of the preview picture"],
|
||||
"description" => ["type" => "text", "comment" => ""],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["id"],
|
||||
"uri-id-url" => ["UNIQUE", "uri-id", "url"],
|
||||
]
|
||||
],
|
||||
"post-tag" => [
|
||||
"comment" => "post relation to tags",
|
||||
"fields" => [
|
||||
|
|
|
@ -39,12 +39,6 @@
|
|||
|
||||
{{include file="field_input.tpl" field=$photo}}
|
||||
|
||||
|
||||
{{if $allow_remote_self eq 1}}
|
||||
<h4>{{$label_remote_self}}</h4>
|
||||
{{include file="field_select.tpl" field=$remote_self}}
|
||||
{{/if}}
|
||||
|
||||
<input type="submit" name="submit" value="{{$lbl_submit}}" />
|
||||
|
||||
</form>
|
||||
|
|
|
@ -69,6 +69,10 @@
|
|||
{{include file="field_select.tpl" field=$fetch_further_information}}
|
||||
{{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}}
|
||||
{{/if}}
|
||||
{{if $allow_remote_self}}
|
||||
{{include file="field_select.tpl" field=$remote_self}}
|
||||
{{/if}}
|
||||
|
||||
{{include file="field_checkbox.tpl" field=$hidden}}
|
||||
|
||||
<div id="contact-edit-info-wrapper">
|
||||
|
|
|
@ -41,12 +41,6 @@
|
|||
|
||||
{{include file="field_input.tpl" field=$photo}}
|
||||
|
||||
|
||||
{{if $allow_remote_self eq 1}}
|
||||
<h4>{{$label_remote_self}}</h4>
|
||||
{{include file="field_select.tpl" field=$remote_self}}
|
||||
{{/if}}
|
||||
|
||||
<div class="pull-right settings-submit-wrapper" >
|
||||
<button type="submit" name="submit" class="btn btn-primary" value="{{$lbl_submit}}">{{$lbl_submit}}</button>
|
||||
</div>
|
||||
|
|
|
@ -135,6 +135,10 @@
|
|||
{{include file="field_select.tpl" field=$fetch_further_information}}
|
||||
{{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}}
|
||||
{{/if}}
|
||||
{{if $allow_remote_self}}
|
||||
{{include file="field_select.tpl" field=$remote_self}}
|
||||
{{/if}}
|
||||
|
||||
{{include file="field_checkbox.tpl" field=$hidden}}
|
||||
|
||||
<div class="pull-right settings-submit-wrapper" >
|
||||
|
|
|
@ -70,6 +70,10 @@
|
|||
{{include file="field_select.tpl" field=$fetch_further_information}}
|
||||
{{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}}
|
||||
{{/if}}
|
||||
{{if $allow_remote_self}}
|
||||
{{include file="field_select.tpl" field=$remote_self}}
|
||||
{{/if}}
|
||||
|
||||
{{include file="field_checkbox.tpl" field=$hidden}}
|
||||
|
||||
<div id="contact-edit-info-wrapper">
|
||||
|
|
Loading…
Reference in a new issue