mirror of
https://git.friendi.ca/friendica/friendica.git
synced 2025-06-08 22:24:26 +02:00
Merge remote-tracking branch 'upstream/2021.12-rc' into user-banner
This commit is contained in:
commit
0450536621
61 changed files with 1503 additions and 1650 deletions
|
@ -52,7 +52,7 @@ class Activity extends BaseApi
|
|||
$res = Item::performActivity($request['id'], $this->parameters['verb'], $uid);
|
||||
|
||||
if ($res) {
|
||||
if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
|
||||
if (($this->parameters['extension'] ?? '') == 'xml') {
|
||||
$ok = 'true';
|
||||
} else {
|
||||
$ok = 'ok';
|
||||
|
|
87
src/Module/Api/Friendica/Group/Create.php
Normal file
87
src/Module/Api/Friendica/Group/Create.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica\Group;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* API endpoint: /api/friendica/group_create
|
||||
*/
|
||||
class Create extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$name = $this->getRequestValue($request, 'name', '');
|
||||
$json = json_decode($request['json'], true);
|
||||
$users = $json['user'];
|
||||
|
||||
// error if no name specified
|
||||
if ($name == '') {
|
||||
throw new HTTPException\BadRequestException('group name not specified');
|
||||
}
|
||||
|
||||
// error message if specified group name already exists
|
||||
if (DBA::exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) {
|
||||
throw new HTTPException\BadRequestException('group name already exists');
|
||||
}
|
||||
|
||||
// Check if the group needs to be reactivated
|
||||
if (DBA::exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => true])) {
|
||||
$reactivate_group = true;
|
||||
}
|
||||
|
||||
// create group
|
||||
$ret = Group::create($uid, $name);
|
||||
if ($ret) {
|
||||
$gid = Group::getIdByName($uid, $name);
|
||||
} else {
|
||||
throw new HTTPException\BadRequestException('other API error');
|
||||
}
|
||||
|
||||
// add members
|
||||
$erroraddinguser = false;
|
||||
$errorusers = [];
|
||||
foreach ($users as $user) {
|
||||
$cid = $user['cid'];
|
||||
if (DBA::exists('contact', ['id' => $cid, 'uid' => $uid])) {
|
||||
Group::addMember($gid, $cid);
|
||||
} else {
|
||||
$erroraddinguser = true;
|
||||
$errorusers[] = $cid;
|
||||
}
|
||||
}
|
||||
|
||||
// return success message incl. missing users in array
|
||||
$status = ($erroraddinguser ? 'missing user' : ((isset($reactivate_group) && $reactivate_group) ? 'reactivated' : 'ok'));
|
||||
|
||||
$result = ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers];
|
||||
|
||||
$this->response->exit('group_create', ['$result' => $result], $this->parameters['extension'] ?? null);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@
|
|||
namespace Friendica\Module\Api\Friendica\Group;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Network\HTTPException\BadRequestException;
|
||||
|
|
79
src/Module/Api/Friendica/Group/Show.php
Normal file
79
src/Module/Api/Friendica/Group/Show.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica\Group;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* API endpoint: /api/friendica/group_show
|
||||
*/
|
||||
class Show extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
$type = $this->getRequestValue($this->parameters, 'extension', 'json');
|
||||
|
||||
// params
|
||||
$gid = $this->getRequestValue($request, 'gid', 0);
|
||||
|
||||
// get data of the specified group id or all groups if not specified
|
||||
if ($gid != 0) {
|
||||
$groups = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid, 'id' => $gid]);
|
||||
|
||||
// error message if specified gid is not in database
|
||||
if (!DBA::isResult($groups)) {
|
||||
throw new HTTPException\BadRequestException('gid not available');
|
||||
}
|
||||
} else {
|
||||
$groups = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid]);
|
||||
}
|
||||
|
||||
// loop through all groups and retrieve all members for adding data in the user array
|
||||
$grps = [];
|
||||
foreach ($groups as $rr) {
|
||||
$members = Contact\Group::getById($rr['id']);
|
||||
$users = [];
|
||||
|
||||
if ($type == 'xml') {
|
||||
$user_element = 'users';
|
||||
$k = 0;
|
||||
foreach ($members as $member) {
|
||||
$users[$k++.':user'] = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
|
||||
}
|
||||
} else {
|
||||
$user_element = 'user';
|
||||
foreach ($members as $member) {
|
||||
$users[] = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
|
||||
}
|
||||
}
|
||||
$grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users];
|
||||
}
|
||||
|
||||
$this->response->exit('group_update', ['group' => $grps], $this->parameters['extension'] ?? null);
|
||||
}
|
||||
}
|
|
@ -38,9 +38,9 @@ class Update extends BaseApi
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$gid = $request['gid'] ?? 0;
|
||||
$name = $request['name'] ?? '';
|
||||
$json = json_decode($_POST['json'], true);
|
||||
$gid = $this->getRequestValue($request, 'gid', 0);
|
||||
$name = $this->getRequestValue($request, 'name', '');
|
||||
$json = json_decode($request['json'], true);
|
||||
$users = $json['user'];
|
||||
|
||||
// error if no name specified
|
||||
|
|
|
@ -43,7 +43,7 @@ class Notification extends BaseApi
|
|||
$notifications[] = new ApiNotification($Notify);
|
||||
}
|
||||
|
||||
if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
|
||||
if (($this->parameters['extension'] ?? '') == 'xml') {
|
||||
$xmlnotes = [];
|
||||
foreach ($notifications as $notification) {
|
||||
$xmlnotes[] = ['@attributes' => $notification->toArray()];
|
||||
|
|
|
@ -47,7 +47,9 @@ class Seen extends BaseApi
|
|||
throw new BadRequestException('Invalid argument count');
|
||||
}
|
||||
|
||||
$id = intval($_REQUEST['id'] ?? 0);
|
||||
$id = intval($request['id'] ?? 0);
|
||||
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
try {
|
||||
$Notify = DI::notify()->selectOneById($id);
|
||||
|
@ -65,8 +67,6 @@ class Seen extends BaseApi
|
|||
if ($Notify->otype === Notification\ObjectType::ITEM) {
|
||||
$item = Post::selectFirstForUser($uid, [], ['id' => $Notify->iid, 'uid' => $uid]);
|
||||
if (DBA::isResult($item)) {
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
// we found the item, return it to the user
|
||||
$ret = [DI::twitterStatus()->createFromUriId($item['uri-id'], $item['uid'], $include_entities)->toArray()];
|
||||
$data = ['status' => $ret];
|
||||
|
|
65
src/Module/Api/Friendica/Photo.php
Normal file
65
src/Module/Api/Friendica/Photo.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Photo extends BaseApi
|
||||
{
|
||||
/** @var FriendicaPhoto */
|
||||
private $friendicaPhoto;
|
||||
|
||||
|
||||
public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->friendicaPhoto = $friendicaPhoto;
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
$type = $this->getRequestValue($this->parameters, 'extension', 'json');
|
||||
|
||||
if (empty($request['photo_id'])) {
|
||||
throw new HTTPException\BadRequestException('No photo id.');
|
||||
}
|
||||
|
||||
$scale = (!empty($request['scale']) ? intval($request['scale']) : false);
|
||||
$photo_id = $request['photo_id'];
|
||||
|
||||
// prepare json/xml output with data from database for the requested photo
|
||||
$data = ['photo' => $this->friendicaPhoto->createFromId($photo_id, $scale, $uid, $type)];
|
||||
|
||||
$this->response->exit('statuses', $data, $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
97
src/Module/Api/Friendica/Photo/Create.php
Normal file
97
src/Module/Api/Friendica/Photo/Create.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica\Photo;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\ACL;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* API endpoint: /api/friendica/photo/create
|
||||
*/
|
||||
class Create extends BaseApi
|
||||
{
|
||||
/** @var FriendicaPhoto */
|
||||
private $friendicaPhoto;
|
||||
|
||||
|
||||
public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->friendicaPhoto = $friendicaPhoto;
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
$type = $this->getRequestValue($this->parameters, 'extension', 'json');
|
||||
|
||||
// input params
|
||||
$desc = $this->getRequestValue($request, 'desc');
|
||||
$album = $this->getRequestValue($request, 'album');
|
||||
$allow_cid = $this->getRequestValue($request, 'allow_cid');
|
||||
$deny_cid = $this->getRequestValue($request, 'deny_cid');
|
||||
$allow_gid = $this->getRequestValue($request, 'allow_gid');
|
||||
$deny_gid = $this->getRequestValue($request, 'deny_gid');
|
||||
|
||||
// do several checks on input parameters
|
||||
// we do not allow calls without album string
|
||||
if ($album == null) {
|
||||
throw new HTTPException\BadRequestException('no albumname specified');
|
||||
}
|
||||
|
||||
// error if no media posted in create-mode
|
||||
if (empty($_FILES['media'])) {
|
||||
// Output error
|
||||
throw new HTTPException\BadRequestException('no media data submitted');
|
||||
}
|
||||
|
||||
// checks on acl strings provided by clients
|
||||
$acl_input_error = false;
|
||||
$acl_input_error |= !ACL::isValidContact($allow_cid, $uid);
|
||||
$acl_input_error |= !ACL::isValidContact($deny_cid, $uid);
|
||||
$acl_input_error |= !ACL::isValidGroup($allow_gid, $uid);
|
||||
$acl_input_error |= !ACL::isValidGroup($deny_gid, $uid);
|
||||
if ($acl_input_error) {
|
||||
throw new HTTPException\BadRequestException('acl data invalid');
|
||||
}
|
||||
// now let's upload the new media in create-mode
|
||||
$photo = Photo::upload($uid, $_FILES['media'], $album, trim($allow_cid), trim($allow_gid), trim($deny_cid), trim($deny_gid), $desc);
|
||||
|
||||
// return success of updating or error message
|
||||
if (!empty($photo)) {
|
||||
$data = ['photo' => $this->friendicaPhoto->createFromId($photo['resource_id'], null, $uid, $type)];
|
||||
$this->response->exit('photo_create', $data, $this->parameters['extension'] ?? null);
|
||||
} else {
|
||||
throw new HTTPException\InternalServerErrorException('unknown error - uploading photo failed, see Friendica log for more information');
|
||||
}
|
||||
}
|
||||
}
|
82
src/Module/Api/Friendica/Photo/Lists.php
Normal file
82
src/Module/Api/Friendica/Photo/Lists.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica\Photo;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Returns all lists the user subscribes to.
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
|
||||
*/
|
||||
class Lists extends BaseApi
|
||||
{
|
||||
/** @var FriendicaPhoto */
|
||||
private $friendicaPhoto;
|
||||
|
||||
|
||||
public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->friendicaPhoto = $friendicaPhoto;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
$type = $this->getRequestValue($this->parameters, 'extension', 'json');
|
||||
|
||||
$photos = Photo::selectToArray(['resource-id'], ["`uid` = ? AND NOT `photo-type` IN (?, ?)", $uid, Photo::CONTACT_AVATAR, Photo::CONTACT_BANNER],
|
||||
['order' => ['id'], 'group_by' => ['resource-id']]);
|
||||
|
||||
$data = ['photo' => []];
|
||||
if (DBA::isResult($photos)) {
|
||||
foreach ($photos as $photo) {
|
||||
$element = $this->friendicaPhoto->createFromId($photo['resource-id'], null, $uid, 'json', false);
|
||||
|
||||
$element['thumb'] = end($element['link']);
|
||||
unset($element['link']);
|
||||
|
||||
if ($type == 'xml') {
|
||||
$thumb = $element['thumb'];
|
||||
unset($element['thumb']);
|
||||
$data['photo'][] = ['@attributes' => $element, '1' => $thumb];
|
||||
} else {
|
||||
$data['photo'][] = $element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->exit('statuses', $data, $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
152
src/Module/Api/Friendica/Photo/Update.php
Normal file
152
src/Module/Api/Friendica/Photo/Update.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica\Photo;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\ACL;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* API endpoint: /api/friendica/photo/update
|
||||
*/
|
||||
class Update extends BaseApi
|
||||
{
|
||||
/** @var FriendicaPhoto */
|
||||
private $friendicaPhoto;
|
||||
|
||||
|
||||
public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->friendicaPhoto = $friendicaPhoto;
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
$type = $this->getRequestValue($this->parameters, 'extension', 'json');
|
||||
|
||||
// input params
|
||||
$photo_id = $this->getRequestValue($request, 'photo_id');
|
||||
$desc = $this->getRequestValue($request, 'desc');
|
||||
$album = $this->getRequestValue($request, 'album');
|
||||
$album_new = $this->getRequestValue($request, 'album_new');
|
||||
$allow_cid = $this->getRequestValue($request, 'allow_cid');
|
||||
$deny_cid = $this->getRequestValue($request, 'deny_cid');
|
||||
$allow_gid = $this->getRequestValue($request, 'allow_gid');
|
||||
$deny_gid = $this->getRequestValue($request, 'deny_gid');
|
||||
|
||||
// do several checks on input parameters
|
||||
// we do not allow calls without album string
|
||||
if ($album == null) {
|
||||
throw new HTTPException\BadRequestException('no albumname specified');
|
||||
}
|
||||
|
||||
// check if photo is existing in databasei
|
||||
if (!Photo::exists(['resource-id' => $photo_id, 'uid' => $uid, 'album' => $album])) {
|
||||
throw new HTTPException\BadRequestException('photo not available');
|
||||
}
|
||||
|
||||
// checks on acl strings provided by clients
|
||||
$acl_input_error = false;
|
||||
$acl_input_error |= !ACL::isValidContact($allow_cid, $uid);
|
||||
$acl_input_error |= !ACL::isValidContact($deny_cid, $uid);
|
||||
$acl_input_error |= !ACL::isValidGroup($allow_gid, $uid);
|
||||
$acl_input_error |= !ACL::isValidGroup($deny_gid, $uid);
|
||||
if ($acl_input_error) {
|
||||
throw new HTTPException\BadRequestException('acl data invalid');
|
||||
}
|
||||
|
||||
$updated_fields = [];
|
||||
|
||||
if (!is_null($desc)) {
|
||||
$updated_fields['desc'] = $desc;
|
||||
}
|
||||
|
||||
if (!is_null($album_new)) {
|
||||
$updated_fields['album'] = $album_new;
|
||||
}
|
||||
|
||||
if (!is_null($allow_cid)) {
|
||||
$allow_cid = trim($allow_cid);
|
||||
$updated_fields['allow_cid'] = $allow_cid;
|
||||
}
|
||||
|
||||
if (!is_null($deny_cid)) {
|
||||
$deny_cid = trim($deny_cid);
|
||||
$updated_fields['deny_cid'] = $deny_cid;
|
||||
}
|
||||
|
||||
if (!is_null($allow_gid)) {
|
||||
$allow_gid = trim($allow_gid);
|
||||
$updated_fields['allow_gid'] = $allow_gid;
|
||||
}
|
||||
|
||||
if (!is_null($deny_gid)) {
|
||||
$deny_gid = trim($deny_gid);
|
||||
$updated_fields['deny_gid'] = $deny_gid;
|
||||
}
|
||||
|
||||
$result = false;
|
||||
if (count($updated_fields) > 0) {
|
||||
$nothingtodo = false;
|
||||
$result = Photo::update($updated_fields, ['uid' => $uid, 'resource-id' => $photo_id, 'album' => $album]);
|
||||
} else {
|
||||
$nothingtodo = true;
|
||||
}
|
||||
|
||||
if (!empty($_FILES['media'])) {
|
||||
$nothingtodo = false;
|
||||
$photo = Photo::upload($uid, $_FILES['media'], $album, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc, $photo_id);
|
||||
if (!empty($photo)) {
|
||||
$data = ['photo' => $this->friendicaPhoto->createFromId($photo['resource_id'], null, $uid, $type)];
|
||||
$this->response->exit('photo_update', $data, $this->parameters['extension'] ?? null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// return success of updating or error message
|
||||
if ($result) {
|
||||
$answer = ['result' => 'updated', 'message' => 'Image id `' . $photo_id . '` has been updated.'];
|
||||
$this->response->exit('photo_update', ['$result' => $answer], $this->parameters['extension'] ?? null);
|
||||
return;
|
||||
} else {
|
||||
if ($nothingtodo) {
|
||||
$answer = ['result' => 'cancelled', 'message' => 'Nothing to update for image id `' . $photo_id . '`.'];
|
||||
$this->response->exit('photo_update', ['$result' => $answer], $this->parameters['extension'] ?? null);
|
||||
return;
|
||||
}
|
||||
throw new HTTPException\InternalServerErrorException('unknown error - update photo entry in database failed');
|
||||
}
|
||||
|
||||
throw new HTTPException\InternalServerErrorException('unknown error - this error on uploading or updating a photo should never happen');
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ class Show extends BaseApi
|
|||
$profile = self::formatProfile($profile, $profileFields);
|
||||
|
||||
$profiles = [];
|
||||
if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
|
||||
if (($this->parameters['extension'] ?? '') == 'xml') {
|
||||
$profiles['0:profile'] = $profile;
|
||||
} else {
|
||||
$profiles[] = $profile;
|
||||
|
|
|
@ -31,7 +31,7 @@ class Test extends BaseApi
|
|||
{
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
|
||||
if (($this->parameters['extension'] ?? '') == 'xml') {
|
||||
$ok = 'true';
|
||||
} else {
|
||||
$ok = 'ok';
|
||||
|
|
|
@ -40,16 +40,17 @@ class Conversation extends BaseApi
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$id = $this->parameters['id'] ?? 0;
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
$count = $_REQUEST['count'] ?? 20;
|
||||
$page = $_REQUEST['page'] ?? 1;
|
||||
$id = $this->getRequestValue($this->parameters, 'id', 0);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
if ($id == 0) {
|
||||
$id = $_REQUEST['id'] ?? 0;
|
||||
$id = $request['id'] ?? 0;
|
||||
}
|
||||
|
||||
Logger::info(BaseApi::LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
|
||||
|
@ -82,8 +83,6 @@ class Conversation extends BaseApi
|
|||
throw new BadRequestException("There is no status with id $id.");
|
||||
}
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -37,7 +37,7 @@ class Media extends BaseApi
|
|||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
Logger::info('Photo post', ['request' => $_REQUEST, 'files' => $_FILES]);
|
||||
Logger::info('Photo post', ['request' => $request, 'files' => $_FILES]);
|
||||
|
||||
if (empty($_FILES['file'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
|
|
|
@ -31,7 +31,7 @@ class RateLimitStatus extends BaseApi
|
|||
{
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
|
||||
if (($this->parameters['extension'] ?? '') == 'xml') {
|
||||
$hash = [
|
||||
'remaining-hits' => '150',
|
||||
'@attributes' => ["type" => "integer"],
|
||||
|
|
|
@ -56,7 +56,7 @@ class UpdateProfile extends BaseApi
|
|||
|
||||
Profile::publishUpdate($uid);
|
||||
|
||||
$skip_status = $request['skip_status'] ?? false;
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
|
||||
$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
|
||||
|
||||
|
|
72
src/Module/Api/Twitter/Account/UpdateProfileImage.php
Normal file
72
src/Module/Api/Twitter/Account/UpdateProfileImage.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Twitter\Account;
|
||||
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* updates the profile image for the user (either a specified profile or the default profile)
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image
|
||||
*/
|
||||
class UpdateProfileImage extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// get mediadata from image or media (Twitter call api/account/update_profile_image provides image)
|
||||
if (!empty($_FILES['image'])) {
|
||||
$media = $_FILES['image'];
|
||||
} elseif (!empty($_FILES['media'])) {
|
||||
$media = $_FILES['media'];
|
||||
}
|
||||
|
||||
// error if image data is missing
|
||||
if (empty($media)) {
|
||||
throw new HTTPException\BadRequestException('no media data submitted');
|
||||
}
|
||||
|
||||
// save new profile image
|
||||
$resource_id = Photo::uploadAvatar($uid, $media);
|
||||
if (empty($resource_id)) {
|
||||
throw new HTTPException\InternalServerErrorException('image upload failed');
|
||||
}
|
||||
|
||||
// output for client
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
|
||||
$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
|
||||
|
||||
// "verified" isn't used here in the standard
|
||||
unset($user_info['verified']);
|
||||
|
||||
// "uid" is only needed for some internal stuff, so remove it from here
|
||||
unset($user_info['uid']);
|
||||
|
||||
$this->response->exit('user', ['user' => $user_info], $this->parameters['extension'] ?? null);
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ class VerifyCredentials extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
$skip_status = $_REQUEST['skip_status'] ?? false;
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
|
||||
$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
|
||||
|
||||
|
|
|
@ -37,17 +37,14 @@ class Ids extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -37,18 +37,15 @@ class Lists extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -52,8 +52,10 @@ class Destroy extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
$id = filter_var($request['id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
$verbose = filter_var($request['friendica_verbose'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
$id = $this->getRequestValue($request, 'id', 0);
|
||||
$id = $this->getRequestValue($this->parameters, 'id', $id);
|
||||
|
||||
$verbose = $this->getRequestValue($request, 'friendica_verbose', false);
|
||||
|
||||
$parenturi = $request['friendica_parenturi'] ?? '';
|
||||
|
||||
|
@ -64,11 +66,6 @@ class Destroy extends BaseApi
|
|||
return;
|
||||
}
|
||||
|
||||
// BadRequestException if no id specified (for clients using Twitter API)
|
||||
if ($id == 0) {
|
||||
throw new BadRequestException('Message id not specified');
|
||||
}
|
||||
|
||||
// add parent-uri to sql command if specified by calling app
|
||||
$sql_extra = ($parenturi != "" ? " AND `parent-uri` = '" . DBA::escape($parenturi) . "'" : "");
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ abstract class DirectMessagesEndpoint extends BaseApi
|
|||
protected function getMessages(array $request, int $uid, array $condition)
|
||||
{
|
||||
// params
|
||||
$count = filter_var($request['count'] ?? 20, FILTER_VALIDATE_INT, ['options' => ['max_range' => 100]]);
|
||||
$page = filter_var($request['page'] ?? 1, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
|
||||
$since_id = filter_var($request['since_id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
$max_id = filter_var($request['max_id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
$min_id = filter_var($request['min_id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
$verbose = filter_var($request['friendica_verbose'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
$verbose = $this->getRequestValue($request, 'friendica_verbose', false);
|
||||
|
||||
// pagination
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
@ -84,7 +84,7 @@ abstract class DirectMessagesEndpoint extends BaseApi
|
|||
$params['order'] = ['id'];
|
||||
}
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $_REQUEST['user_id'] ?? 0, 0);
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, 0);
|
||||
if (!empty($cid)) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
|
|
|
@ -45,10 +45,11 @@ class Favorites extends BaseApi
|
|||
Logger::info(BaseApi::LOG_PREFIX . 'for {self}', ['module' => 'api', 'action' => 'favorites']);
|
||||
|
||||
// params
|
||||
$since_id = $request['since_id'] ?? 0;
|
||||
$max_id = $request['max_id'] ?? 0;
|
||||
$count = $request['count'] ?? 20;
|
||||
$page = $request['page'] ?? 1;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -64,8 +65,6 @@ class Favorites extends BaseApi
|
|||
|
||||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -37,22 +37,15 @@ class Ids extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||
$profile_url = filter_input(INPUT_GET, 'profile_url');
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
|
||||
// Friendica-specific
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['relation-cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -37,23 +37,16 @@ class Lists extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||
$profile_url = filter_input(INPUT_GET, 'profile_url');
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
|
||||
// Friendica-specific
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['relation-cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -37,22 +37,15 @@ class Ids extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||
$profile_url = filter_input(INPUT_GET, 'profile_url');
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
|
||||
// Friendica-specific
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -37,23 +37,16 @@ class Lists extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||
$profile_url = filter_input(INPUT_GET, 'profile_url');
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$skip_status = $this->getRequestValue($request, 'skip_status', false);
|
||||
$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
|
||||
// Friendica-specific
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -37,17 +37,14 @@ class Incoming extends ContactEndpoint
|
|||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// Expected value for user_id parameter: public/user contact id
|
||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||
'default' => self::DEFAULT_COUNT,
|
||||
'min_range' => 1,
|
||||
'max_range' => self::MAX_COUNT,
|
||||
]]);
|
||||
$cursor = $this->getRequestValue($request, 'cursor', -1);
|
||||
$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
|
||||
$count = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
|
||||
|
||||
// Friendica-specific
|
||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
|
||||
|
||||
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ class Show extends ContactEndpoint
|
|||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
$source_cid = BaseApi::getContactIDForSearchterm($_REQUEST['source_screen_name'] ?? '', '', $_REQUEST['source_id'] ?? 0, $uid);
|
||||
$source_cid = BaseApi::getContactIDForSearchterm($request['source_screen_name'] ?? '', '', $request['source_id'] ?? 0, $uid);
|
||||
|
||||
$target_cid = BaseApi::getContactIDForSearchterm($_REQUEST['target_screen_name'] ?? '', '', $_REQUEST['target_id'] ?? 0, $uid);
|
||||
$target_cid = BaseApi::getContactIDForSearchterm($request['target_screen_name'] ?? '', '', $request['target_id'] ?? 0, $uid);
|
||||
|
||||
$source = Contact::getById($source_cid);
|
||||
if (empty($source)) {
|
||||
|
|
85
src/Module/Api/Twitter/Lists/Create.php
Normal file
85
src/Module/Api/Twitter/Lists/Create.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Update information about a group.
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update
|
||||
*/
|
||||
class Create extends BaseApi
|
||||
{
|
||||
/** @var friendicaGroup */
|
||||
private $friendicaGroup;
|
||||
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->friendicaGroup = $friendicaGroup;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$name = $this->getRequestValue($request, 'name', '');
|
||||
|
||||
if ($name == '') {
|
||||
throw new HTTPException\BadRequestException('group name not specified');
|
||||
}
|
||||
|
||||
// error message if specified group name already exists
|
||||
if ($this->dba->exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) {
|
||||
throw new HTTPException\BadRequestException('group name already exists');
|
||||
}
|
||||
|
||||
$ret = Group::create($uid, $name);
|
||||
if ($ret) {
|
||||
$gid = Group::getIdByName($uid, $name);
|
||||
} else {
|
||||
throw new HTTPException\BadRequestException('other API error');
|
||||
}
|
||||
|
||||
$grp = $this->friendicaGroup->createFromId($gid);
|
||||
|
||||
$this->response->exit('statuses', ['lists' => ['lists' => $grp]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
83
src/Module/Api/Twitter/Lists/Destroy.php
Normal file
83
src/Module/Api/Twitter/Lists/Destroy.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Delete a group.
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy
|
||||
*/
|
||||
class Destroy extends BaseApi
|
||||
{
|
||||
/** @var friendicaGroup */
|
||||
private $friendicaGroup;
|
||||
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->friendicaGroup = $friendicaGroup;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$gid = $this->getRequestValue($request, 'list_id', 0);
|
||||
|
||||
// error if no gid specified
|
||||
if ($gid == 0) {
|
||||
throw new HTTPException\BadRequestException('gid not specified');
|
||||
}
|
||||
|
||||
// get data of the specified group id
|
||||
$group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
|
||||
// error message if specified gid is not in database
|
||||
if (!$group) {
|
||||
throw new HTTPException\BadRequestException('gid not available');
|
||||
}
|
||||
|
||||
$list = $this->friendicaGroup->createFromId($gid);
|
||||
|
||||
if (Group::remove($gid)) {
|
||||
$this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,32 +19,25 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Friendica;
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\BaseApi;
|
||||
require_once __DIR__ . '/../../../../include/api.php';
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
/**
|
||||
* api/friendica
|
||||
* Returns all lists the user subscribes to.
|
||||
*
|
||||
* @package Friendica\Module\Api\Friendica
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
|
||||
*/
|
||||
class Index extends BaseApi
|
||||
class Lists extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
}
|
||||
|
||||
protected function delete(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
echo api_call(DI::args()->getCommand(), $this->parameters['extension'] ?? 'json');
|
||||
exit();
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// This is a dummy endpoint
|
||||
$ret = [];
|
||||
$this->response->exit('statuses', ["lists_list" => $ret], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
69
src/Module/Api/Twitter/Lists/Ownership.php
Normal file
69
src/Module/Api/Twitter/Lists/Ownership.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Returns all groups the user owns.
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships
|
||||
*/
|
||||
class Ownership extends BaseApi
|
||||
{
|
||||
/** @var friendicaGroup */
|
||||
private $friendicaGroup;
|
||||
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->friendicaGroup = $friendicaGroup;
|
||||
}
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
$groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid]);
|
||||
|
||||
// loop through all groups
|
||||
$lists = [];
|
||||
foreach ($groups as $group) {
|
||||
$lists[] = $this->friendicaGroup->createFromId($group['id']);
|
||||
}
|
||||
|
||||
$this->response->exit('statuses', ['lists' => ['lists' => $lists]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
|
@ -21,12 +21,18 @@
|
|||
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Factory\Api\Twitter\Status as TwitterStatus;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Network\HTTPException\BadRequestException;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Returns recent statuses from users in the specified group.
|
||||
|
@ -35,26 +41,41 @@ use Friendica\Network\HTTPException\BadRequestException;
|
|||
*/
|
||||
class Statuses extends BaseApi
|
||||
{
|
||||
/** @var TwitterStatus */
|
||||
private $twitterStatus;
|
||||
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(Database $dba, TwitterStatus $twitterStatus, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->twitterStatus = $twitterStatus;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
if (empty($request['list_id'])) {
|
||||
throw new BadRequestException('list_id not specified');
|
||||
throw new HTTPException\BadRequestException('list_id not specified');
|
||||
}
|
||||
|
||||
// params
|
||||
$count = $request['count'] ?? 20;
|
||||
$page = $request['page'] ?? 1;
|
||||
$since_id = $request['since_id'] ?? 0;
|
||||
$max_id = $request['max_id'] ?? 0;
|
||||
$exclude_replies = (!empty($request['exclude_replies']) ? 1 : 0);
|
||||
$conversation_id = $request['conversation_id'] ?? 0;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
|
||||
$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
$groups = DBA::selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]);
|
||||
$groups = $this->dba->selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]);
|
||||
$gids = array_column($groups, 'contact-id');
|
||||
$condition = ['uid' => $uid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'contact-id' => $gids];
|
||||
$condition = DBA::mergeConditions($condition, ["`id` > ?", $since_id]);
|
||||
|
@ -63,7 +84,7 @@ class Statuses extends BaseApi
|
|||
$condition[0] .= " AND `id` <= ?";
|
||||
$condition[] = $max_id;
|
||||
}
|
||||
if ($exclude_replies > 0) {
|
||||
if ($exclude_replies) {
|
||||
$condition[0] .= ' AND `gravity` = ?';
|
||||
$condition[] = GRAVITY_PARENT;
|
||||
}
|
||||
|
@ -75,13 +96,11 @@ class Statuses extends BaseApi
|
|||
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
|
||||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$items = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$items[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
while ($status = $this->dba->fetch($statuses)) {
|
||||
$items[] = $this->twitterStatus->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
}
|
||||
DBA::close($statuses);
|
||||
$this->dba->close($statuses);
|
||||
|
||||
$this->response->exit('statuses', ['status' => $items], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
|
|
84
src/Module/Api/Twitter/Lists/Update.php
Normal file
84
src/Module/Api/Twitter/Lists/Update.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Twitter\Lists;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Group;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Update information about a group.
|
||||
*
|
||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update
|
||||
*/
|
||||
class Update extends BaseApi
|
||||
{
|
||||
/** @var friendicaGroup */
|
||||
private $friendicaGroup;
|
||||
|
||||
/** @var Database */
|
||||
private $dba;
|
||||
|
||||
public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->friendicaGroup = $friendicaGroup;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
// params
|
||||
$gid = $this->getRequestValue($request, 'list_id', 0);
|
||||
$name = $this->getRequestValue($request, 'name', '');
|
||||
|
||||
// error if no gid specified
|
||||
if ($gid == 0) {
|
||||
throw new HTTPException\BadRequestException('gid not specified');
|
||||
}
|
||||
|
||||
// get data of the specified group id
|
||||
$group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
|
||||
// error message if specified gid is not in database
|
||||
if (!$group) {
|
||||
throw new HTTPException\BadRequestException('gid not available');
|
||||
}
|
||||
|
||||
if (Group::update($gid, $name)) {
|
||||
$list = $this->friendicaGroup->createFromId($gid);
|
||||
|
||||
$this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,26 +41,21 @@ class Tweets extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
if (empty($_REQUEST['q'])) {
|
||||
if (empty($request['q'])) {
|
||||
throw new BadRequestException('q parameter is required.');
|
||||
}
|
||||
|
||||
$searchTerm = trim(rawurldecode($_REQUEST['q']));
|
||||
$searchTerm = trim(rawurldecode($request['q']));
|
||||
|
||||
$data['status'] = [];
|
||||
|
||||
$count = 15;
|
||||
|
||||
$exclude_replies = !empty($_REQUEST['exclude_replies']);
|
||||
if (!empty($_REQUEST['rpp'])) {
|
||||
$count = $_REQUEST['rpp'];
|
||||
} elseif (!empty($_REQUEST['count'])) {
|
||||
$count = $_REQUEST['count'];
|
||||
}
|
||||
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
$page = $_REQUEST['page'] ?? 1;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$count = $this->getRequestValue($request, 'rpp', $count);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -115,8 +110,6 @@ class Tweets extends BaseApi
|
|||
|
||||
$statuses = $statuses ?: Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
namespace Friendica\Module\Api\Twitter\Statuses;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
@ -40,17 +39,15 @@ class Destroy extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
if (!empty($this->parameters['id'])) {
|
||||
$id = (int)$this->parameters['id'];
|
||||
} elseif (!empty($request['id'])) {
|
||||
$id = (int)$request['id'];
|
||||
} else {
|
||||
$id = $this->getRequestValue($request, 'id', 0);
|
||||
$id = $this->getRequestValue($this->parameters, 'id', $id);
|
||||
if (empty($id)) {
|
||||
throw new BadRequestException('An id is missing.');
|
||||
}
|
||||
|
||||
$this->logger->notice('API: api_statuses_destroy: ' . $id);
|
||||
|
||||
$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$ret = DI::twitterStatus()->createFromItemId($id, $uid, $include_entities)->toArray();
|
||||
|
||||
|
|
|
@ -43,12 +43,13 @@ class HomeTimeline extends BaseApi
|
|||
// get last network messages
|
||||
|
||||
// params
|
||||
$count = $_REQUEST['count'] ?? 20;
|
||||
$page = $_REQUEST['page'] ?? 0;
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
$exclude_replies = !empty($_REQUEST['exclude_replies']);
|
||||
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -71,8 +72,6 @@ class HomeTimeline extends BaseApi
|
|||
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
|
||||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
$idarray = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
|
|
|
@ -42,10 +42,11 @@ class Mentions extends BaseApi
|
|||
// get last network messages
|
||||
|
||||
// params
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
$count = $_REQUEST['count'] ?? 20;
|
||||
$page = $_REQUEST['page'] ?? 1;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -72,8 +73,6 @@ class Mentions extends BaseApi
|
|||
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
|
||||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -38,12 +38,11 @@ class NetworkPublicTimeline extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
|
||||
// pagination
|
||||
$count = $_REQUEST['count'] ?? 20;
|
||||
$page = $_REQUEST['page'] ?? 1;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -58,8 +57,6 @@ class NetworkPublicTimeline extends BaseApi
|
|||
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
|
||||
$statuses = Post::selectForUser($uid, Item::DISPLAY_FIELDLIST, $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -41,12 +41,13 @@ class PublicTimeline extends BaseApi
|
|||
// get last network messages
|
||||
|
||||
// params
|
||||
$count = $_REQUEST['count'] ?? 20;
|
||||
$page = $_REQUEST['page'] ?? 1;
|
||||
$since_id = $_REQUEST['since_id'] ?? 0;
|
||||
$max_id = $_REQUEST['max_id'] ?? 0;
|
||||
$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
|
||||
$conversation_id = $_REQUEST['conversation_id'] ?? 0;
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
|
||||
$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -78,8 +79,6 @@ class PublicTimeline extends BaseApi
|
|||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
}
|
||||
|
||||
$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
|
@ -44,11 +44,9 @@ class Retweet extends BaseApi
|
|||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (!empty($this->parameters['id'])) {
|
||||
$id = (int)$this->parameters['id'];
|
||||
} elseif (!empty($request['id'])) {
|
||||
$id = (int)$request['id'];
|
||||
} else {
|
||||
$id = $this->getRequestValue($request, 'id', 0);
|
||||
$id = $this->getRequestValue($this->parameters, 'id', $id);
|
||||
if (empty($id)) {
|
||||
throw new BadRequestException('An id is missing.');
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ class Show extends BaseApi
|
|||
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
||||
if (empty($this->parameters['id'])) {
|
||||
$id = intval($request['id'] ?? 0);
|
||||
} else {
|
||||
$id = (int)$this->parameters['id'];
|
||||
$id = $this->getRequestValue($request, 'id', 0);
|
||||
$id = $this->getRequestValue($this->parameters, 'id', $id);
|
||||
if (empty($id)) {
|
||||
throw new BadRequestException('An id is missing.');
|
||||
}
|
||||
|
||||
Logger::notice('API: api_statuses_show: ' . $id);
|
||||
|
@ -79,7 +79,7 @@ class Show extends BaseApi
|
|||
throw new BadRequestException(sprintf("There is no status or conversation with the id %d.", $id));
|
||||
}
|
||||
|
||||
$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
|
|
|
@ -42,15 +42,14 @@ class UserTimeline extends BaseApi
|
|||
|
||||
Logger::info('api_statuses_user_timeline', ['api_user' => $uid, '_REQUEST' => $request]);
|
||||
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$since_id = $request['since_id'] ?? 0;
|
||||
$max_id = $request['max_id'] ?? 0;
|
||||
$exclude_replies = !empty($request['exclude_replies']);
|
||||
$conversation_id = $request['conversation_id'] ?? 0;
|
||||
|
||||
// pagination
|
||||
$count = $request['count'] ?? 20;
|
||||
$page = $request['page'] ?? 1;
|
||||
$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
|
||||
$count = $this->getRequestValue($request, 'count', 20, 1, 100);
|
||||
$page = $this->getRequestValue($request, 'page', 1, 1);
|
||||
$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
|
||||
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
|
||||
$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
|
||||
$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
|
||||
$include_entities = $this->getRequestValue($request, 'include_entities', false);
|
||||
|
||||
$start = max(0, ($page - 1) * $count);
|
||||
|
||||
|
@ -74,8 +73,6 @@ class UserTimeline extends BaseApi
|
|||
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
|
||||
$statuses = Post::selectForUser($uid, [], $condition, $params);
|
||||
|
||||
$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
|
||||
|
||||
$ret = [];
|
||||
while ($status = DBA::fetch($statuses)) {
|
||||
$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue