]> git.mxchange.org Git - friendica.git/commitdiff
API: The legacy API finally moved
authorMichael <heluecht@pirati.ca>
Sat, 15 Jan 2022 21:38:19 +0000 (21:38 +0000)
committerMichael <heluecht@pirati.ca>
Sat, 15 Jan 2022 21:38:19 +0000 (21:38 +0000)
23 files changed:
include/api.php [deleted file]
src/Content/Text/BBCode.php
src/DI.php
src/Factory/Api/Friendica/Group.php [new file with mode: 0644]
src/Factory/Api/Friendica/Photo.php [new file with mode: 0644]
src/Module/Api/Friendica/Group/Create.php [new file with mode: 0644]
src/Module/Api/Friendica/Group/Show.php [new file with mode: 0644]
src/Module/Api/Friendica/Index.php [deleted file]
src/Module/Api/Friendica/Photo.php [new file with mode: 0644]
src/Module/Api/Friendica/Photo/Create.php [new file with mode: 0644]
src/Module/Api/Friendica/Photo/Lists.php [new file with mode: 0644]
src/Module/Api/Friendica/Photo/Update.php [new file with mode: 0644]
src/Module/Api/Twitter/Account/UpdateProfileImage.php [new file with mode: 0644]
src/Module/Api/Twitter/Lists/Create.php [new file with mode: 0644]
src/Module/Api/Twitter/Lists/Destroy.php [new file with mode: 0644]
src/Module/Api/Twitter/Lists/Lists.php [new file with mode: 0644]
src/Module/Api/Twitter/Lists/Ownership.php [new file with mode: 0644]
src/Module/Api/Twitter/Lists/Update.php [new file with mode: 0644]
src/Object/Api/Friendica/Group.php [new file with mode: 0644]
src/Util/Images.php
src/Util/ParseUrl.php
static/routes.config.php
tests/legacy/ApiTest.php

diff --git a/include/api.php b/include/api.php
deleted file mode 100644 (file)
index 9e8b3dd..0000000
+++ /dev/null
@@ -1,857 +0,0 @@
-<?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/>.
- *
- * Friendica implementation of statusnet/twitter API
- *
- * @file include/api.php
- * @todo Automatically detect if incoming data is HTML or BBCode
- */
-
-use Friendica\App;
-use Friendica\Core\ACL;
-use Friendica\Core\Logger;
-use Friendica\Database\DBA;
-use Friendica\DI;
-use Friendica\Model\Contact;
-use Friendica\Model\Group;
-use Friendica\Model\Photo;
-use Friendica\Model\Post;
-use Friendica\Module\BaseApi;
-use Friendica\Network\HTTPException;
-
-$API = [];
-
-/**
- * Register a function to be the endpoint for defined API path.
- *
- * @param string $path   API URL path, relative to DI::baseUrl()
- * @param string $func   Function name to call on path request
- */
-function api_register_func($path, $func)
-{
-       global $API;
-
-       $API[$path] = [
-               'func'   => $func,
-       ];
-
-       // Workaround for hotot
-       $path = str_replace("api/", "api/1.1/", $path);
-
-       $API[$path] = [
-               'func'   => $func,
-       ];
-}
-
-/**
- * Main API entry point
- *
- * Authenticate user, call registered API function, set HTTP headers
- *
- * @param App\Arguments $args The app arguments (optional, will retrieved by the DI-Container in case of missing)
- * @return string|array API call result
- * @throws Exception
- */
-function api_call($command, $extension)
-{
-       global $API;
-
-       Logger::info('Legacy API call', ['command' => $command, 'extension' => $extension]);
-
-       try {
-               foreach ($API as $p => $info) {
-                       if (strpos($command, $p) === 0) {
-                               Logger::debug(BaseApi::LOG_PREFIX . 'parameters', ['module' => 'api', 'action' => 'call', 'parameters' => $_REQUEST]);
-
-                               $stamp =  microtime(true);
-                               $return = call_user_func($info['func'], $extension);
-                               $duration = floatval(microtime(true) - $stamp);
-
-                               Logger::info(BaseApi::LOG_PREFIX . 'duration {duration}', ['module' => 'api', 'action' => 'call', 'duration' => round($duration, 2)]);
-
-                               DI::profiler()->saveLog(DI::logger(), BaseApi::LOG_PREFIX . 'performance');
-
-                               if (false === $return) {
-                                       /*
-                                               * api function returned false withour throw an
-                                               * exception. This should not happend, throw a 500
-                                               */
-                                       throw new HTTPException\InternalServerErrorException();
-                               }
-
-                               switch ($extension) {
-                                       case "xml":
-                                               header("Content-Type: text/xml");
-                                               break;
-                                       case "json":
-                                               header("Content-Type: application/json");
-                                               if (!empty($return)) {
-                                                       $json = json_encode(end($return));
-                                                       if (!empty($_GET['callback'])) {
-                                                               $json = $_GET['callback'] . "(" . $json . ")";
-                                                       }
-                                                       $return = $json;
-                                               }
-                                               break;
-                                       case "rss":
-                                               header("Content-Type: application/rss+xml");
-                                               $return  = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
-                                               break;
-                                       case "atom":
-                                               header("Content-Type: application/atom+xml");
-                                               $return = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
-                                               break;
-                               }
-                               return $return;
-                       }
-               }
-
-               Logger::warning(BaseApi::LOG_PREFIX . 'not implemented', ['module' => 'api', 'action' => 'call', 'query' => DI::args()->getQueryString()]);
-               throw new HTTPException\NotFoundException();
-       } catch (HTTPException $e) {
-               Logger::notice(BaseApi::LOG_PREFIX . 'got exception', ['module' => 'api', 'action' => 'call', 'query' => DI::args()->getQueryString(), 'error' => $e]);
-               DI::apiResponse()->error($e->getCode(), $e->getDescription(), $e->getMessage(), $extension);
-       }
-}
-
-/**
- *
- * @param string $type
- * @param int    $scale
- * @param string $photo_id
- *
- * @return array
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\NotFoundException
- * @throws HTTPException\UnauthorizedException
- */
-function prepare_photo_data($type, $scale, $photo_id, $uid)
-{
-       $scale_sql = ($scale === false ? "" : sprintf("AND scale=%d", intval($scale)));
-       $data_sql = ($scale === false ? "" : "data, ");
-
-       // added allow_cid, allow_gid, deny_cid, deny_gid to output as string like stored in database
-       // clients needs to convert this in their way for further processing
-       $r = DBA::toArray(DBA::p(
-               "SELECT $data_sql `resource-id`, `created`, `edited`, `title`, `desc`, `album`, `filename`,
-                                       `type`, `height`, `width`, `datasize`, `profile`, `allow_cid`, `deny_cid`, `allow_gid`, `deny_gid`,
-                                       MIN(`scale`) AS `minscale`, MAX(`scale`) AS `maxscale`
-                       FROM `photo` WHERE `uid` = ? AND `resource-id` = ? $scale_sql GROUP BY
-                                  `resource-id`, `created`, `edited`, `title`, `desc`, `album`, `filename`,
-                                  `type`, `height`, `width`, `datasize`, `profile`, `allow_cid`, `deny_cid`, `allow_gid`, `deny_gid`",
-               $uid,
-               $photo_id
-       ));
-
-       $typetoext = [
-               'image/jpeg' => 'jpg',
-               'image/png' => 'png',
-               'image/gif' => 'gif'
-       ];
-
-       // prepare output data for photo
-       if (DBA::isResult($r)) {
-               $data = ['photo' => $r[0]];
-               $data['photo']['id'] = $data['photo']['resource-id'];
-               if ($scale !== false) {
-                       $data['photo']['data'] = base64_encode($data['photo']['data']);
-               } else {
-                       unset($data['photo']['datasize']); //needed only with scale param
-               }
-               if ($type == "xml") {
-                       $data['photo']['links'] = [];
-                       for ($k = intval($data['photo']['minscale']); $k <= intval($data['photo']['maxscale']); $k++) {
-                               $data['photo']['links'][$k . ":link"]["@attributes"] = ["type" => $data['photo']['type'],
-                                                                               "scale" => $k,
-                                                                               "href" => DI::baseUrl() . "/photo/" . $data['photo']['resource-id'] . "-" . $k . "." . $typetoext[$data['photo']['type']]];
-                       }
-               } else {
-                       $data['photo']['link'] = [];
-                       // when we have profile images we could have only scales from 4 to 6, but index of array always needs to start with 0
-                       $i = 0;
-                       for ($k = intval($data['photo']['minscale']); $k <= intval($data['photo']['maxscale']); $k++) {
-                               $data['photo']['link'][$i] = DI::baseUrl() . "/photo/" . $data['photo']['resource-id'] . "-" . $k . "." . $typetoext[$data['photo']['type']];
-                               $i++;
-                       }
-               }
-               unset($data['photo']['resource-id']);
-               unset($data['photo']['minscale']);
-               unset($data['photo']['maxscale']);
-       } else {
-               throw new HTTPException\NotFoundException();
-       }
-
-       // retrieve item element for getting activities (like, dislike etc.) related to photo
-       $condition = ['uid' => $uid, 'resource-id' => $photo_id];
-       $item = Post::selectFirst(['id', 'uid', 'uri', 'uri-id', 'parent', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid'], $condition);
-       if (!DBA::isResult($item)) {
-               throw new HTTPException\NotFoundException('Photo-related item not found.');
-       }
-
-       $data['photo']['friendica_activities'] = DI::friendicaActivities()->createFromUriId($item['uri-id'], $item['uid'], $type);
-
-       // retrieve comments on photo
-       $condition = ["`parent` = ? AND `uid` = ? AND `gravity` IN (?, ?)",
-               $item['parent'], $uid, GRAVITY_PARENT, GRAVITY_COMMENT];
-
-       $statuses = Post::selectForUser($uid, [], $condition);
-
-       // prepare output of comments
-       $commentData = [];
-       while ($status = DBA::fetch($statuses)) {
-               $commentData[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'])->toArray();
-       }
-       DBA::close($statuses);
-
-       $comments = [];
-       if ($type == "xml") {
-               $k = 0;
-               foreach ($commentData as $comment) {
-                       $comments[$k++ . ":comment"] = $comment;
-               }
-       } else {
-               foreach ($commentData as $comment) {
-                       $comments[] = $comment;
-               }
-       }
-       $data['photo']['friendica_comments'] = $comments;
-
-       // include info if rights on photo and rights on item are mismatching
-       $rights_mismatch = $data['photo']['allow_cid'] != $item['allow_cid'] ||
-               $data['photo']['deny_cid'] != $item['deny_cid'] ||
-               $data['photo']['allow_gid'] != $item['allow_gid'] ||
-               $data['photo']['deny_gid'] != $item['deny_gid'];
-       $data['photo']['rights_mismatch'] = $rights_mismatch;
-
-       return $data;
-}
-
-/**
- * TWITTER API
- */
-
-/**
- * Returns all lists the user subscribes to.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
- */
-function api_lists_list($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
-       $ret = [];
-       /// @TODO $ret is not filled here?
-       return DI::apiResponse()->formatData('lists', $type, ["lists_list" => $ret]);
-}
-
-api_register_func('api/lists/list', 'api_lists_list', true);
-api_register_func('api/lists/subscriptions', 'api_lists_list', true);
-
-/**
- * Returns all groups the user owns.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships
- */
-function api_lists_ownerships($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $user_info = DI::twitterUser()->createFromUserId($uid, true)->toArray();
-
-       $groups = DBA::select('group', [], ['deleted' => 0, 'uid' => $uid]);
-
-       // loop through all groups
-       $lists = [];
-       foreach ($groups as $group) {
-               if ($group['visible']) {
-                       $mode = 'public';
-               } else {
-                       $mode = 'private';
-               }
-               $lists[] = [
-                       'name' => $group['name'],
-                       'id' => intval($group['id']),
-                       'id_str' => (string) $group['id'],
-                       'user' => $user_info,
-                       'mode' => $mode
-               ];
-       }
-       return DI::apiResponse()->formatData("lists", $type, ['lists' => ['lists' => $lists]]);
-}
-
-api_register_func('api/lists/ownerships', 'api_lists_ownerships', true);
-
-/**
- * list all photos of the authenticated user
- *
- * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
- * @return string|array
- * @throws HTTPException\ForbiddenException
- * @throws HTTPException\InternalServerErrorException
- */
-function api_fr_photos_list($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
-       $uid = BaseApi::getCurrentUserID();
-
-       $r = DBA::toArray(DBA::p(
-               "SELECT `resource-id`, MAX(scale) AS `scale`, `album`, `filename`, `type`, MAX(`created`) AS `created`,
-               MAX(`edited`) AS `edited`, MAX(`desc`) AS `desc` FROM `photo`
-               WHERE `uid` = ? AND NOT `photo-type` IN (?, ?) GROUP BY `resource-id`, `album`, `filename`, `type`",
-               $uid, Photo::CONTACT_AVATAR, Photo::CONTACT_BANNER
-       ));
-       $typetoext = [
-               'image/jpeg' => 'jpg',
-               'image/png' => 'png',
-               'image/gif' => 'gif'
-       ];
-       $data = ['photo'=>[]];
-       if (DBA::isResult($r)) {
-               foreach ($r as $rr) {
-                       $photo = [];
-                       $photo['id'] = $rr['resource-id'];
-                       $photo['album'] = $rr['album'];
-                       $photo['filename'] = $rr['filename'];
-                       $photo['type'] = $rr['type'];
-                       $thumb = DI::baseUrl() . "/photo/" . $rr['resource-id'] . "-" . $rr['scale'] . "." . $typetoext[$rr['type']];
-                       $photo['created'] = $rr['created'];
-                       $photo['edited'] = $rr['edited'];
-                       $photo['desc'] = $rr['desc'];
-
-                       if ($type == "xml") {
-                               $data['photo'][] = ["@attributes" => $photo, "1" => $thumb];
-                       } else {
-                               $photo['thumb'] = $thumb;
-                               $data['photo'][] = $photo;
-                       }
-               }
-       }
-       return DI::apiResponse()->formatData("photos", $type, $data);
-}
-
-api_register_func('api/friendica/photos/list', 'api_fr_photos_list', true);
-
-/**
- * upload a new photo or change an existing photo
- *
- * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
- * @return string|array
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\NotFoundException
- */
-function api_fr_photo_create_update($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
-       $uid = BaseApi::getCurrentUserID();
-
-       // input params
-       $photo_id  = $_REQUEST['photo_id']  ?? null;
-       $desc      = $_REQUEST['desc']      ?? null;
-       $album     = $_REQUEST['album']     ?? null;
-       $album_new = $_REQUEST['album_new'] ?? null;
-       $allow_cid = $_REQUEST['allow_cid'] ?? null;
-       $deny_cid  = $_REQUEST['deny_cid' ] ?? null;
-       $allow_gid = $_REQUEST['allow_gid'] ?? null;
-       $deny_gid  = $_REQUEST['deny_gid' ] ?? null;
-
-       // do several checks on input parameters
-       // we do not allow calls without album string
-       if ($album == null) {
-               throw new HTTPException\BadRequestException("no albumname specified");
-       }
-       // if photo_id == null --> we are uploading a new photo
-       if ($photo_id == null) {
-               $mode = "create";
-
-               // error if no media posted in create-mode
-               if (empty($_FILES['media'])) {
-                       // Output error
-                       throw new HTTPException\BadRequestException("no media data submitted");
-               }
-
-               // album_new will be ignored in create-mode
-               $album_new = "";
-       } else {
-               $mode = "update";
-
-               // 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");
-       }
-       // now let's upload the new media in create-mode
-       if ($mode == "create") {
-               $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 = prepare_photo_data($type, false, $photo['resource_id'], $uid);
-                       return DI::apiResponse()->formatData("photo_create", $type, $data);
-               } else {
-                       throw new HTTPException\InternalServerErrorException("unknown error - uploading photo failed, see Friendica log for more information");
-               }
-       }
-
-       // now let's do the changes in update-mode
-       if ($mode == "update") {
-               $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 = prepare_photo_data($type, false, $photo['resource_id'], $uid);
-                               return DI::apiResponse()->formatData("photo_update", $type, $data);
-                       }
-               }
-
-               // return success of updating or error message
-               if ($result) {
-                       $answer = ['result' => 'updated', 'message' => 'Image id `' . $photo_id . '` has been updated.'];
-                       return DI::apiResponse()->formatData("photo_update", $type, ['$result' => $answer]);
-               } else {
-                       if ($nothingtodo) {
-                               $answer = ['result' => 'cancelled', 'message' => 'Nothing to update for image id `' . $photo_id . '`.'];
-                               return DI::apiResponse()->formatData("photo_update", $type, ['$result' => $answer]);
-                       }
-                       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");
-}
-
-api_register_func('api/friendica/photo/create', 'api_fr_photo_create_update', true);
-api_register_func('api/friendica/photo/update', 'api_fr_photo_create_update', true);
-
-/**
- * returns the details of a specified photo id, if scale is given, returns the photo data in base 64
- *
- * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
- * @return string|array
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\NotFoundException
- */
-function api_fr_photo_detail($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
-       $uid = BaseApi::getCurrentUserID();
-
-       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 = prepare_photo_data($type, $scale, $photo_id, $uid);
-
-       return DI::apiResponse()->formatData("photo_detail", $type, $data);
-}
-
-api_register_func('api/friendica/photo', 'api_fr_photo_detail', true);
-
-/**
- * updates the profile image for the user (either a specified profile or the default profile)
- *
- * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
- *
- * @return string|array
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\NotFoundException
- * @see   https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image
- */
-function api_account_update_profile_image($type)
-{
-       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 = $_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']);
-
-       return DI::apiResponse()->formatData("user", $type, ['user' => $user_info]);
-}
-
-api_register_func('api/account/update_profile_image', 'api_account_update_profile_image', true);
-
-/**
- * Return all or a specified group of the user with the containing contacts.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- */
-function api_friendica_group_show($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $gid = $_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) {
-                               $user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
-                               $users[$k++.":user"] = $user;
-                       }
-               } else {
-                       $user_element = "user";
-                       foreach ($members as $member) {
-                               $user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
-                               $users[] = $user;
-                       }
-               }
-               $grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users];
-       }
-       return DI::apiResponse()->formatData("groups", $type, ['group' => $grps]);
-}
-
-api_register_func('api/friendica/group_show', 'api_friendica_group_show', true);
-
-/**
- * Delete a group.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy
- */
-function api_lists_destroy($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $gid = $_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 = 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::remove($gid)) {
-               $list = [
-                       'name' => $group['name'],
-                       'id' => intval($gid),
-                       'id_str' => (string) $gid,
-                       'user' => DI::twitterUser()->createFromUserId($uid, true)->toArray()
-               ];
-
-               return DI::apiResponse()->formatData("lists", $type, ['lists' => $list]);
-       }
-}
-
-api_register_func('api/lists/destroy', 'api_lists_destroy', true);
-
-/**
- * Create the specified group with the posted array of contacts.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- */
-function api_friendica_group_create($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $name = $_REQUEST['name'] ?? '';
-       $json = json_decode($_POST['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];
-
-       return DI::apiResponse()->formatData("group_create", $type, ['result' => $result]);
-}
-
-api_register_func('api/friendica/group_create', 'api_friendica_group_create', true);
-
-/**
- * Create a new group.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create
- */
-function api_lists_create($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $name = $_REQUEST['name'] ?? '';
-
-       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');
-       }
-
-       $ret = Group::create($uid, $name);
-       if ($ret) {
-               $gid = Group::getIdByName($uid, $name);
-       } else {
-               throw new HTTPException\BadRequestException('other API error');
-       }
-
-       $grp = [
-               'name' => $name,
-               'id' => intval($gid),
-               'id_str' => (string) $gid,
-               'user' => DI::twitterUser()->createFromUserId($uid, true)->toArray()
-       ];
-
-       return DI::apiResponse()->formatData("lists", $type, ['lists' => $grp]);
-}
-
-api_register_func('api/lists/create', 'api_lists_create', true);
-
-/**
- * Update information about a group.
- *
- * @param string $type Return type (atom, rss, xml, json)
- *
- * @return array|string
- * @throws HTTPException\BadRequestException
- * @throws HTTPException\ForbiddenException
- * @throws ImagickException
- * @throws HTTPException\InternalServerErrorException
- * @throws HTTPException\UnauthorizedException
- * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update
- */
-function api_lists_update($type)
-{
-       BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
-       $uid = BaseApi::getCurrentUserID();
-
-       // params
-       $gid = $_REQUEST['list_id'] ?? 0;
-       $name = $_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 = 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 = [
-                       'name' => $name,
-                       'id' => intval($gid),
-                       'id_str' => (string) $gid,
-                       'user' => DI::twitterUser()->createFromUserId($uid, true)->toArray()
-               ];
-
-               return DI::apiResponse()->formatData("lists", $type, ['lists' => $list]);
-       }
-}
-
-api_register_func('api/lists/update', 'api_lists_update', true);
index a3244aafc329ae06645e36b654c50ee85aa4b81b..1f638c2f52353bd0e7e342945d79bfc75cdb09e0 100644 (file)
@@ -1134,7 +1134,7 @@ class BBCode
                switch ($simplehtml) {
                        case self::API:
                                $text = ($is_quote_share? '<br>' : '') .
-                               '<b><a href="' . $attributes['link'] . '">' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b><br>\n" .
+                               '<b><a href="' . $attributes['link'] . '">' . html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b><br>\n" .
                                '<blockquote class="shared_content">' . $content . '</blockquote>';
                                break;
                        case self::DIASPORA:
index 89b102afc330ce51e9d544409d543f6207e5cdb2..992e2c649d515a017cddf4411d4e54df3ebe8b0f 100644 (file)
@@ -270,6 +270,22 @@ abstract class DI
                return self::$dice->create(Factory\Api\Friendica\Activities::class);
        }
 
+       /**
+        * @return Factory\Api\Friendica\Group
+        */
+       public static function friendicaGroup()
+       {
+               return self::$dice->create(Factory\Api\Friendica\Group::class);
+       }
+
+       /**
+        * @return Factory\Api\Friendica\Photo
+        */
+       public static function friendicaPhoto()
+       {
+               return self::$dice->create(Factory\Api\Friendica\Photo::class);
+       }
+
        /**
         * @return Factory\Api\Mastodon\Account
         */
diff --git a/src/Factory/Api/Friendica/Group.php b/src/Factory/Api/Friendica/Group.php
new file mode 100644 (file)
index 0000000..945971c
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Factory\Api\Friendica;
+
+use Friendica\BaseFactory;
+use Friendica\Database\DBA;
+use Friendica\Network\HTTPException;
+use Psr\Log\LoggerInterface;
+use Friendica\Factory\Api\Twitter\User as TwitterUser;
+
+class Group extends BaseFactory
+{
+       /** @var twitterUser entity */
+       private $twitterUser;
+
+       public function __construct(LoggerInterface $logger, TwitterUser $twitteruser)
+       {
+               parent::__construct($logger);
+
+               $this->twitterUser = $twitteruser;
+       }
+
+       /**
+        * @param int $id id of the group
+        * @return array
+        * @throws HTTPException\InternalServerErrorException
+        */
+       public function createFromId(int $id): array
+       {
+               $group = DBA::selectFirst('group', [], ['id' => $id, 'deleted' => false]);
+               if (empty($group)) {
+                       return [];
+               }
+
+               $user   = $this->twitterUser->createFromUserId($group['uid'])->toArray();
+               $object = new \Friendica\Object\Api\Friendica\Group($group, $user);
+
+               return $object->toArray();
+       }
+}
diff --git a/src/Factory/Api/Friendica/Photo.php b/src/Factory/Api/Friendica/Photo.php
new file mode 100644 (file)
index 0000000..2a2f2be
--- /dev/null
@@ -0,0 +1,154 @@
+<?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\Factory\Api\Friendica;
+
+use Friendica\App\BaseURL;
+use Friendica\BaseFactory;
+use Friendica\Database\DBA;
+use Friendica\Factory\Api\Twitter\Status;
+use Friendica\Model\Photo as ModelPhoto;
+use Friendica\Model\Post;
+use Friendica\Network\HTTPException;
+use Psr\Log\LoggerInterface;
+use Friendica\Util\Images;
+
+class Photo extends BaseFactory
+{
+       /** @var BaseURL */
+       private $baseUrl;
+       /** @var Status */
+       private $status;
+       /** @var Activities */
+       private $activities;
+
+       public function __construct(LoggerInterface $logger, BaseURL $baseURL, Status $status, Activities $activities)
+       {
+               parent::__construct($logger);
+
+               $this->activities = $activities;
+               $this->status     = $status;
+               $this->baseUrl    = $baseURL;
+       }
+
+       /**
+        * @param string $photo_id
+        * @param int    $scale
+        * @param int    $uid
+        * @param string $type
+        * @return Array
+        */
+       public function createFromId(string $photo_id, int $scale = null, int $uid, string $type = 'json', bool $with_posts = true): array
+       {
+               $fields = ['resource-id', 'created', 'edited', 'title', 'desc', 'album', 'filename','type',
+               'height', 'width', 'datasize', 'profile', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid',
+               'backend-class', 'backend-ref', 'id', 'scale'];
+
+               $condition = ['uid' => $uid, 'resource-id' => $photo_id];
+               if (is_int($scale)) {
+                       $fields = array_merge(['data'], $fields);
+                       $condition['scale'] = $scale;
+               }
+
+               $photos = ModelPhoto::selectToArray($fields, $condition);
+               if (empty($photos)) {
+                       throw new HTTPException\NotFoundException();
+               }
+               $data = $photos[0];
+               $data['id'] = $data['resource-id'];
+               if (is_int($scale)) {
+                       $data['data'] = base64_encode(ModelPhoto::getImageDataForPhoto($data));
+               } else {
+                       unset($data['datasize']); //needed only with scale param
+               }
+
+               if ($type == 'xml') {
+                       $data['links'] = [];
+               } else {
+                       $data['link'] = [];
+               }
+
+               foreach ($photos as $id => $photo) {
+                       $link = $this->baseUrl->get() . '/photo/' . $data['resource-id'] . '-' . $photo['scale'] . Images::getExtensionByMimeType($data['type']);
+                       if ($type == 'xml') {
+                               $data['links'][$photo['scale'] . ':link']['@attributes'] = [
+                                       'type' => $data['type'],
+                                       'scale' => $photo['scale'],
+                                       'href' => $link
+                               ];
+                       } else {
+                               $data['link'][$id] = $link;
+                       }
+               }
+
+               unset($data['backend-class']);
+               unset($data['backend-ref']);
+               unset($data['resource-id']);
+               unset($data['scale']);
+       
+               if ($with_posts) {
+                       // retrieve item element for getting activities (like, dislike etc.) related to photo
+                       $condition = ['uid' => $uid, 'resource-id' => $photo_id];
+                       $item = Post::selectFirst(['id', 'uid', 'uri', 'uri-id', 'parent', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid'], $condition);
+               }
+               if (!empty($item)) {
+                       $data['friendica_activities'] = $this->activities->createFromUriId($item['uri-id'], $item['uid'], $type);
+       
+                       // retrieve comments on photo
+                       $condition = ["`parent` = ? AND `uid` = ? AND `gravity` IN (?, ?)",
+                               $item['parent'], $uid, GRAVITY_PARENT, GRAVITY_COMMENT];
+               
+                       $statuses = Post::selectForUser($uid, [], $condition);
+               
+                       // prepare output of comments
+                       $commentData = [];
+                       while ($status = DBA::fetch($statuses)) {
+                               $commentData[] = $this->status->createFromUriId($status['uri-id'], $status['uid'])->toArray();
+                       }
+                       DBA::close($statuses);
+               
+                       $comments = [];
+                       if ($type == 'xml') {
+                               $k = 0;
+                               foreach ($commentData as $comment) {
+                                       $comments[$k++ . ':comment'] = $comment;
+                               }
+                       } else {
+                               foreach ($commentData as $comment) {
+                                       $comments[] = $comment;
+                               }
+                       }
+                       $data['friendica_comments'] = $comments;
+               
+                       // include info if rights on photo and rights on item are mismatching
+                       $data['rights_mismatch'] = $data['allow_cid'] != $item['allow_cid'] ||
+                               $data['deny_cid'] != $item['deny_cid'] ||
+                               $data['allow_gid'] != $item['allow_gid'] ||
+                               $data['deny_gid'] != $item['deny_gid'];
+               } elseif ($with_posts) {
+                       $data['friendica_activities'] = [];
+                       $data['friendica_comments']   = [];
+                       $data['rights_mismatch'] = false;
+               }
+       
+               return $data;
+       }
+}
\ No newline at end of file
diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Group/Create.php
new file mode 100644 (file)
index 0000000..8544558
--- /dev/null
@@ -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 = $_REQUEST['name'] ?? '';
+               $json = json_decode($_POST['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);
+       }
+}
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
new file mode 100644 (file)
index 0000000..62e13e0
--- /dev/null
@@ -0,0 +1,81 @@
+<?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->parameters['extension'] ?? '';
+       
+               // params
+               $gid = $_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) {
+                                       $user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
+                                       $users[$k++.':user'] = $user;
+                               }
+                       } else {
+                               $user_element = 'user';
+                               foreach ($members as $member) {
+                                       $user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
+                                       $users[] = $user;
+                               }
+                       }
+                       $grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users];
+               }
+
+               $this->response->exit('group_update', ['group' => $grps], $this->parameters['extension'] ?? null);
+       }
+}
diff --git a/src/Module/Api/Friendica/Index.php b/src/Module/Api/Friendica/Index.php
deleted file mode 100644 (file)
index c3eeda2..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?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\DI;
-use Friendica\Module\BaseApi;
-require_once __DIR__ . '/../../../../include/api.php';
-
-/**
- * api/friendica
- *
- * @package Friendica\Module\Api\Friendica
- */
-class Index 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();
-       }
-}
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
new file mode 100644 (file)
index 0000000..a27abb3
--- /dev/null
@@ -0,0 +1,49 @@
+<?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\DI;
+use Friendica\Model\Contact;
+use Friendica\Module\BaseApi;
+use Friendica\Network\HTTPException;
+
+class Activity extends BaseApi
+{
+       protected function post(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
+               $uid  = BaseApi::getCurrentUserID();
+               $type = $this->parameters['extension'] ?? '';
+
+               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' => DI::friendicaPhoto()->createFromId($photo_id, $scale, $uid, $type)];
+       
+               $this->response->exit('statuses', $data, $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+       }
+}
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
new file mode 100644 (file)
index 0000000..fe99a17
--- /dev/null
@@ -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\Core\ACL;
+use Friendica\DI;
+use Friendica\Model\Photo;
+use Friendica\Module\BaseApi;
+use Friendica\Network\HTTPException;
+
+/**
+ * API endpoint: /api/friendica/photo/create
+ */
+class Create extends BaseApi
+{
+       protected function post(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
+               $uid  = BaseApi::getCurrentUserID();
+               $type = $this->parameters['extension'] ?? '';
+
+               // input params
+               $desc      = $_REQUEST['desc']      ?? null;
+               $album     = $_REQUEST['album']     ?? null;
+               $allow_cid = $_REQUEST['allow_cid'] ?? null;
+               $deny_cid  = $_REQUEST['deny_cid' ] ?? null;
+               $allow_gid = $_REQUEST['allow_gid'] ?? null;
+               $deny_gid  = $_REQUEST['deny_gid' ] ?? null;
+       
+               // 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' => DI::friendicaPhoto()->createFromId($photo['resource_id'], null, $uid, $type)];
+                       $this->response->exit('photo_create', $data, $this->parameters['extension'] ?? null);
+                       return;
+               } else {
+                       throw new HTTPException\InternalServerErrorException('unknown error - uploading photo failed, see Friendica log for more information');
+               }
+       }
+}
diff --git a/src/Module/Api/Friendica/Photo/Lists.php b/src/Module/Api/Friendica/Photo/Lists.php
new file mode 100644 (file)
index 0000000..826e32d
--- /dev/null
@@ -0,0 +1,66 @@
+<?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\DI;
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+use Friendica\Model\Photo;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
+               $uid  = BaseApi::getCurrentUserID();
+               $type = $this->parameters['extension'] ?? '';
+
+               $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 = DI::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));
+       }
+}
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
new file mode 100644 (file)
index 0000000..2b489ba
--- /dev/null
@@ -0,0 +1,136 @@
+<?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\Core\ACL;
+use Friendica\DI;
+use Friendica\Model\Photo;
+use Friendica\Module\BaseApi;
+use Friendica\Network\HTTPException;
+
+/**
+ * API endpoint: /api/friendica/photo/update
+ */
+class Update extends BaseApi
+{
+       protected function post(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
+               $uid  = BaseApi::getCurrentUserID();
+               $type = $this->parameters['extension'] ?? '';
+       
+               // input params
+               $photo_id  = $_REQUEST['photo_id']  ?? null;
+               $desc      = $_REQUEST['desc']      ?? null;
+               $album     = $_REQUEST['album']     ?? null;
+               $album_new = $_REQUEST['album_new'] ?? null;
+               $allow_cid = $_REQUEST['allow_cid'] ?? null;
+               $deny_cid  = $_REQUEST['deny_cid' ] ?? null;
+               $allow_gid = $_REQUEST['allow_gid'] ?? null;
+               $deny_gid  = $_REQUEST['deny_gid' ] ?? null;
+       
+               // 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' => DI::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');
+       }
+}
diff --git a/src/Module/Api/Twitter/Account/UpdateProfileImage.php b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
new file mode 100644 (file)
index 0000000..15ca6cf
--- /dev/null
@@ -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 = $_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);
+       }
+}
diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
new file mode 100644 (file)
index 0000000..f39d7bb
--- /dev/null
@@ -0,0 +1,66 @@
+<?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\Database\DBA;
+use Friendica\DI;
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+use Friendica\Model\Group;
+use Friendica\Network\HTTPException;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
+               $uid = BaseApi::getCurrentUserID();
+       
+               // params
+               $name = $_REQUEST['name'] ?? '';
+       
+               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');
+               }
+       
+               $ret = Group::create($uid, $name);
+               if ($ret) {
+                       $gid = Group::getIdByName($uid, $name);
+               } else {
+                       throw new HTTPException\BadRequestException('other API error');
+               }
+       
+               $grp = DI::friendicaGroup()->createFromId($gid);
+       
+               $this->response->exit('statuses', ['lists' => ['lists' => $grp]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+       }
+}
diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php
new file mode 100644 (file)
index 0000000..8e84cb8
--- /dev/null
@@ -0,0 +1,64 @@
+<?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\Database\DBA;
+use Friendica\DI;
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+use Friendica\Model\Group;
+use Friendica\Network\HTTPException;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
+               $uid = BaseApi::getCurrentUserID();
+       
+               // params
+               $gid = $_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 = 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 = DI::friendicaGroup()->createFromId($gid);
+       
+               if (Group::remove($gid)) {
+                       $this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+               }
+       }
+}
diff --git a/src/Module/Api/Twitter/Lists/Lists.php b/src/Module/Api/Twitter/Lists/Lists.php
new file mode 100644 (file)
index 0000000..09d740b
--- /dev/null
@@ -0,0 +1,43 @@
+<?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\Module\BaseApi;
+use Friendica\Model\Contact;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               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));
+       }
+}
diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php
new file mode 100644 (file)
index 0000000..57aa285
--- /dev/null
@@ -0,0 +1,51 @@
+<?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\Database\DBA;
+use Friendica\DI;
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
+               $uid = BaseApi::getCurrentUserID();
+       
+               $groups = DBA::select('group', [], ['deleted' => false, 'uid' => $uid]);
+       
+               // loop through all groups
+               $lists = [];
+               foreach ($groups as $group) {
+                       $lists[] = DI::friendicaGroup()->createFromId($group['id']);
+               }
+
+               $this->response->exit('statuses', ['lists' => ['lists' => $lists]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+       }
+}
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
new file mode 100644 (file)
index 0000000..e78ae27
--- /dev/null
@@ -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\Twitter\Lists;
+
+use Friendica\Database\DBA;
+use Friendica\DI;
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+use Friendica\Model\Group;
+use Friendica\Network\HTTPException;
+
+/**
+ * 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
+{
+       protected function rawContent(array $request = [])
+       {
+               BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
+               $uid = BaseApi::getCurrentUserID();
+       
+               // params
+               $gid  = $_REQUEST['list_id'] ?? 0;
+               $name = $_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 = 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 = DI::friendicaGroup()->createFromId($gid);
+       
+                       $this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+               }
+       }
+}
diff --git a/src/Object/Api/Friendica/Group.php b/src/Object/Api/Friendica/Group.php
new file mode 100644 (file)
index 0000000..36dd6df
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Object\Api\Friendica;
+
+use Friendica\BaseDataTransferObject;
+
+/**
+ * Class Group
+ *
+ *
+ */
+class Group extends BaseDataTransferObject
+{
+       /** @var string */
+       protected $name;
+       /** @var int */
+       protected $id;
+       /** @var string */
+       protected $id_str;
+       /** @var array */
+       protected $user;
+       /** @var string */
+       protected $mode;
+
+       /**
+        * Creates an Group entity array
+        *
+        * @param array $group
+        * @param array $user
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       public function __construct(array $group, array $user)
+       {
+               $this->name   = $group['name'];
+               $this->id     = $group['id'];
+               $this->id_str = (string)$group['id'];
+               $this->user   = $user;
+               $this->mode   = $group['visible'] ? 'public' : 'private';
+       }
+}
index cd4704dcee068018ec0f1a4c4b8a701930e257f6..077509d3cb5e6e1c64105e2a7886bd131cf31be5 100644 (file)
@@ -46,6 +46,30 @@ class Images
                return $m;
        }
 
+       /**
+        * Return file extension for mime type
+        * @param string $mimetype
+        * @return string
+        */
+       public static function getExtensionByMimeType(string $mimetype): string
+       {
+               switch ($mimetype) {
+                       case 'image/png':
+                               $imagetype = IMAGETYPE_PNG;
+                               break;
+
+                       case 'image/gif':
+                               $imagetype = IMAGETYPE_GIF;
+                               break;
+
+                       default:
+                               $imagetype = IMAGETYPE_JPEG;
+                               break;
+               }
+
+               return image_type_to_extension($imagetype);
+       }
+
        /**
         * Returns supported image mimetypes and corresponding file extensions
         *
index c1fcff28e6b2ef380eb3d8ec425a620c1435b4a3..04afc927ba6cec4229c8167a6bcafe66e4c317d9 100644 (file)
@@ -216,6 +216,7 @@ class ParseUrl
 
                $curlResult = DI::httpClient()->get($url, [HttpClientOptions::CONTENT_LENGTH => 1000000]);
                if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
+                       Logger::info('Empty body or error when fetching', ['url' => $url, 'success' => $curlResult->isSuccess(), 'code' => $curlResult->getReturnCode()]);
                        return $siteinfo;
                }
 
index 63c968c6c7ecdb18d26e2aeaeae629a948761786..758462ca034911afa578d667d082471fc415819d 100644 (file)
@@ -42,10 +42,10 @@ $profileRoutes = [
 
 $apiRoutes = [
        '/account' => [
-               '/verify_credentials[.{extension:json|xml|rss|atom}]'      => [Module\Api\Twitter\Account\VerifyCredentials::class, [R::GET         ]],
-               '/rate_limit_status[.{extension:json|xml|rss|atom}]'       => [Module\Api\Twitter\Account\RateLimitStatus::class,   [R::GET         ]],
-               '/update_profile[.{extension:json|xml|rss|atom}]'          => [Module\Api\Twitter\Account\UpdateProfile ::class,    [        R::POST]],
-               '/update_profile_image[.{extension:json|xml|rss|atom}]'    => [Module\Api\Friendica\Index::class,                   [        R::POST]],
+               '/verify_credentials[.{extension:json|xml|rss|atom}]'      => [Module\Api\Twitter\Account\VerifyCredentials::class,  [R::GET         ]],
+               '/rate_limit_status[.{extension:json|xml|rss|atom}]'       => [Module\Api\Twitter\Account\RateLimitStatus::class,    [R::GET         ]],
+               '/update_profile[.{extension:json|xml|rss|atom}]'          => [Module\Api\Twitter\Account\UpdateProfile ::class,     [        R::POST]],
+               '/update_profile_image[.{extension:json|xml|rss|atom}]'    => [Module\Api\Twitter\Account\UpdateProfileImage::class, [        R::POST]],
        ],
 
        '/blocks/ids[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Twitter\Blocks\Ids::class,               [R::GET         ]],
@@ -80,18 +80,18 @@ $apiRoutes = [
                '/direct_messages_setseen[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\DirectMessages\Setseen::class, [        R::POST]],
                '/direct_messages_search[.{extension:json|xml|rss|atom}]'  => [Module\Api\Friendica\DirectMessages\Search ::class, [R::GET         ]],
                '/events[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Friendica\Events\Index::class,           [R::GET         ]],
-               '/group_show[.{extension:json|xml|rss|atom}]'              => [Module\Api\Friendica\Index::class,                  [R::GET         ]],
-               '/group_create[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Index::class,                  [        R::POST]],
+               '/group_show[.{extension:json|xml|rss|atom}]'              => [Module\Api\Friendica\Group\Show::class,             [R::GET         ]],
+               '/group_create[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Group\Create::class,           [        R::POST]],
                '/group_delete[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Group\Delete::class,           [        R::POST]],
                '/group_update[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Group\Update::class,           [        R::POST]],
                '/profile/show[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Profile\Show::class,           [R::GET         ]],
                '/photoalbum/delete[.{extension:json|xml|rss|atom}]'       => [Module\Api\Friendica\Photoalbum\Delete::class,      [        R::POST]],
                '/photoalbum/update[.{extension:json|xml|rss|atom}]'       => [Module\Api\Friendica\Photoalbum\Update::class,      [        R::POST]],
-               '/photos/list[.{extension:json|xml|rss|atom}]'             => [Module\Api\Friendica\Index::class,                  [R::GET         ]],
-               '/photo/create[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Index::class,                  [        R::POST]],
+               '/photos/list[.{extension:json|xml|rss|atom}]'             => [Module\Api\Friendica\Photo\Lists::class,            [R::GET         ]],
+               '/photo/create[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Photo\Create::class,           [        R::POST]],
                '/photo/delete[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Photo\Delete::class,           [        R::POST]],
-               '/photo/update[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Index::class,                  [        R::POST]],
-               '/photo[.{extension:json|xml|rss|atom}]'                   => [Module\Api\Friendica\Index::class,                  [R::GET         ]],
+               '/photo/update[.{extension:json|xml|rss|atom}]'            => [Module\Api\Friendica\Photo\Update::class,           [        R::POST]],
+               '/photo[.{extension:json|xml|rss|atom}]'                   => [Module\Api\Friendica\Photo::class,                  [R::GET         ]],
        ],
 
        '/gnusocial/config[.{extension:json|xml|rss|atom}]'            => [Module\Api\GNUSocial\GNUSocial\Config::class,  [R::GET         ]],
@@ -99,13 +99,13 @@ $apiRoutes = [
        '/help/test[.{extension:json|xml|rss|atom}]'                   => [Module\Api\GNUSocial\Help\Test::class,         [R::GET         ]],
 
        '/lists' => [
-               '/create[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Friendica\Index::class,        [        R::POST]],
-               '/destroy[.{extension:json|xml|rss|atom}]'                 => [Module\Api\Friendica\Index::class,        [        R::POST]],
-               '/list[.{extension:json|xml|rss|atom}]'                    => [Module\Api\Friendica\Index::class,        [R::GET         ]],
-               '/ownerships[.{extension:json|xml|rss|atom}]'              => [Module\Api\Friendica\Index::class,        [R::GET         ]],
-               '/statuses[.{extension:json|xml|rss|atom}]'                => [Module\Api\Twitter\Lists\Statuses::class, [R::GET         ]],
-               '/subscriptions[.{extension:json|xml|rss|atom}]'           => [Module\Api\Friendica\Index::class,        [R::GET         ]],
-               '/update[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Friendica\Index::class,        [        R::POST]],
+               '/create[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Twitter\Lists\Create::class,    [        R::POST]],
+               '/destroy[.{extension:json|xml|rss|atom}]'                 => [Module\Api\Twitter\Lists\Destroy::class,   [        R::POST]],
+               '/list[.{extension:json|xml|rss|atom}]'                    => [Module\Api\Twitter\Lists\Lists::class,     [R::GET         ]],
+               '/ownerships[.{extension:json|xml|rss|atom}]'              => [Module\Api\Twitter\Lists\Ownership::class, [R::GET         ]],
+               '/statuses[.{extension:json|xml|rss|atom}]'                => [Module\Api\Twitter\Lists\Statuses::class,  [R::GET         ]],
+               '/subscriptions[.{extension:json|xml|rss|atom}]'           => [Module\Api\Friendica\Lists\Lists::class,   [R::GET         ]],
+               '/update[.{extension:json|xml|rss|atom}]'                  => [Module\Api\Twitter\Lists\Update::class,    [        R::POST]],
        ],
 
        '/media/upload[.{extension:json|xml|rss|atom}]'                    => [Module\Api\Twitter\Media\Upload::class,             [        R::POST]],
index 075459d0ec7f56cc947312bfb677b34a5d2e5fcf..597f432ff7a2bbb90f72d7521b7b44cfcc0728f5 100644 (file)
@@ -23,7 +23,6 @@
 namespace Friendica\Test\legacy;
 
 use Friendica\App;
-use Friendica\Core\ACL;
 use Friendica\Core\Config\Capability\IManageConfigValues;
 use Friendica\DI;
 use Friendica\Module\BaseApi;
@@ -129,37 +128,6 @@ class ApiTest extends FixtureTest
                BasicAuth::setCurrentUserID($this->selfUser['id']);
        }
 
-       /**
-        * Assert that a list array contains expected keys.
-        *
-        * @param array $list List array
-        *
-        * @return void
-        */
-       private function assertList(array $list = [])
-       {
-               self::assertIsString($list['name']);
-               self::assertIsInt($list['id']);
-               self::assertIsString('string', $list['id_str']);
-               self::assertContains($list['mode'], ['public', 'private']);
-               // We could probably do more checks here.
-       }
-
-       /**
-        * Assert that the string is XML and contain the root element.
-        *
-        * @param string $result       XML string
-        * @param string $root_element Root element name
-        *
-        * @return void
-        */
-       private function assertXml($result = '', $root_element = '')
-       {
-               self::assertStringStartsWith('<?xml version="1.0"?>', $result);
-               self::assertStringContainsString('<' . $root_element, $result);
-               // We could probably do more checks here.
-       }
-
        /**
         * Test the api_user() function.
         *
@@ -214,26 +182,6 @@ class ApiTest extends FixtureTest
                self::assertEquals('Wed Oct 10 00:00:00 +0000 1990', DateTimeFormat::utc('1990-10-10', DateTimeFormat::API));
        }
 
-       /**
-        * Test the api_register_func() function.
-        *
-        * @return void
-        */
-       public function testApiRegisterFunc()
-       {
-               global $API;
-               self::assertNull(
-                       api_register_func(
-                               'api_path',
-                               function () {
-                               },
-                               true,
-                               'method'
-                       )
-               );
-               self::assertTrue(is_callable($API['api_path']['func']));
-       }
-
        /**
         * Test the BasicAuth::getCurrentUserID() function without any login.
         *
@@ -312,166 +260,6 @@ class ApiTest extends FixtureTest
                BasicAuth::getCurrentUserID(true);
        }
 
-       /**
-        * Test the api_call() function.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCall()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return ['data' => ['some_data']];
-                       }
-               ];
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path';
-               $_GET['callback']          = 'callback_name';
-
-               self::assertEquals(
-                       'callback_name(["some_data"])',
-                       api_call('api_path', 'json')
-               );
-       }
-
-       /**
-        * Test the api_call() function with the profiled enabled.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCallWithProfiler()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return ['data' => ['some_data']];
-                       }
-               ];
-
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path';
-
-               $this->config->set('system', 'profiler', true);
-               $this->config->set('rendertime', 'callstack', true);
-               $this->app->callstack = [
-                       'database'       => ['some_function' => 200],
-                       'database_write' => ['some_function' => 200],
-                       'cache'          => ['some_function' => 200],
-                       'cache_write'    => ['some_function' => 200],
-                       'network'        => ['some_function' => 200]
-               ];
-
-               self::assertEquals(
-                       '["some_data"]',
-                       api_call('api_path', 'json')
-               );
-       }
-
-       /**
-        * Test the api_call() function with a JSON result.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCallWithJson()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return ['data' => ['some_data']];
-                       }
-               ];
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path.json';
-
-               self::assertEquals(
-                       '["some_data"]',
-                       api_call('api_path.json', 'json')
-               );
-       }
-
-       /**
-        * Test the api_call() function with an XML result.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCallWithXml()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return 'some_data';
-                       }
-               ];
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path.xml';
-
-               $args = DI::args()->determine($_SERVER, $_GET);
-
-               self::assertEquals(
-                       'some_data',
-                       api_call('api_path.xml', 'xml')
-               );
-       }
-
-       /**
-        * Test the api_call() function with an RSS result.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCallWithRss()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return 'some_data';
-                       }
-               ];
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path.rss';
-
-               self::assertEquals(
-                       '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
-                       'some_data',
-                       api_call('api_path.rss', 'rss')
-               );
-       }
-
-       /**
-        * Test the api_call() function with an Atom result.
-        *
-        * @runInSeparateProcess
-        * @preserveGlobalState disabled
-        */
-       public function testApiCallWithAtom()
-       {
-               global $API;
-               $API['api_path']           = [
-                       'method' => 'method',
-                       'func'   => function () {
-                               return 'some_data';
-                       }
-               ];
-               $_SERVER['REQUEST_METHOD'] = 'method';
-               $_SERVER['QUERY_STRING'] = 'pagename=api_path.atom';
-
-               self::assertEquals(
-                       '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
-                       'some_data',
-                       api_call('api_path.atom', 'atom')
-               );
-       }
-
        /**
         * Test the Arrays::walkRecursive() function.
         *
@@ -511,290 +299,4 @@ class ApiTest extends FixtureTest
                        )
                );
        }
-
-       /**
-        * Test the api_lists_list() function.
-        *
-        * @return void
-        */
-       public function testApiListsList()
-       {
-               $result = api_lists_list('json');
-               self::assertEquals(['lists_list' => []], $result);
-       }
-
-       /**
-        * Test the api_lists_ownerships() function.
-        *
-        * @return void
-        */
-       public function testApiListsOwnerships()
-       {
-               $result = api_lists_ownerships('json');
-               foreach ($result['lists']['lists'] as $list) {
-                       self::assertList($list);
-               }
-       }
-
-       /**
-        * Test the api_lists_ownerships() function without an authenticated user.
-        *
-        * @return void
-        */
-       public function testApiListsOwnershipsWithoutAuthenticatedUser()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
-               BasicAuth::setCurrentUserID();
-               $_SESSION['authenticated'] = false;
-               api_lists_ownerships('json');
-       }
-
-       /**
-        * Test the api_fr_photos_list() function.
-        *
-        * @return void
-        */
-       public function testApiFrPhotosList()
-       {
-               $result = api_fr_photos_list('json');
-               self::assertArrayHasKey('photo', $result);
-       }
-
-       /**
-        * Test the api_fr_photos_list() function without an authenticated user.
-        *
-        * @return void
-        */
-       public function testApiFrPhotosListWithoutAuthenticatedUser()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
-               BasicAuth::setCurrentUserID();
-               $_SESSION['authenticated'] = false;
-               api_fr_photos_list('json');
-       }
-
-       /**
-        * Test the api_fr_photo_create_update() function.
-        */
-       public function testApiFrPhotoCreateUpdate()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
-               api_fr_photo_create_update('json');
-       }
-
-       /**
-        * Test the api_fr_photo_create_update() function without an authenticated user.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoCreateUpdateWithoutAuthenticatedUser()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
-               BasicAuth::setCurrentUserID();
-               $_SESSION['authenticated'] = false;
-               api_fr_photo_create_update('json');
-       }
-
-       /**
-        * Test the api_fr_photo_create_update() function with an album name.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoCreateUpdateWithAlbum()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
-               $_REQUEST['album'] = 'album_name';
-               api_fr_photo_create_update('json');
-       }
-
-       /**
-        * Test the api_fr_photo_create_update() function with the update mode.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoCreateUpdateWithUpdate()
-       {
-               $this->markTestIncomplete('We need to create a dataset for this');
-       }
-
-       /**
-        * Test the api_fr_photo_create_update() function with an uploaded file.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoCreateUpdateWithFile()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_fr_photo_detail() function.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoDetail()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
-               api_fr_photo_detail('json');
-       }
-
-       /**
-        * Test the api_fr_photo_detail() function without an authenticated user.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoDetailWithoutAuthenticatedUser()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
-               BasicAuth::setCurrentUserID();
-               $_SESSION['authenticated'] = false;
-               api_fr_photo_detail('json');
-       }
-
-       /**
-        * Test the api_fr_photo_detail() function with a photo ID.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoDetailWithPhotoId()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\NotFoundException::class);
-               $_REQUEST['photo_id'] = 1;
-               api_fr_photo_detail('json');
-       }
-
-       /**
-        * Test the api_fr_photo_detail() function with a correct photo ID.
-        *
-        * @return void
-        */
-       public function testApiFrPhotoDetailCorrectPhotoId()
-       {
-               $this->markTestIncomplete('We need to create a dataset for this.');
-       }
-
-       /**
-        * Test the api_account_update_profile_image() function.
-        *
-        * @return void
-        */
-       public function testApiAccountUpdateProfileImage()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
-               api_account_update_profile_image('json');
-       }
-
-       /**
-        * Test the api_account_update_profile_image() function without an authenticated user.
-        *
-        * @return void
-        */
-       public function testApiAccountUpdateProfileImageWithoutAuthenticatedUser()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\UnauthorizedException::class);
-               BasicAuth::setCurrentUserID();
-               $_SESSION['authenticated'] = false;
-               api_account_update_profile_image('json');
-       }
-
-       /**
-        * Test the api_account_update_profile_image() function with an uploaded file.
-        *
-        * @return void
-        */
-       public function testApiAccountUpdateProfileImageWithUpload()
-       {
-               $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class);
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the save_media_to_database() function.
-        *
-        * @return void
-        */
-       public function testSaveMediaToDatabase()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the post_photo_item() function.
-        *
-        * @return void
-        */
-       public function testPostPhotoItem()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the prepare_photo_data() function.
-        *
-        * @return void
-        */
-       public function testPreparePhotoData()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_friendica_group_show() function.
-        *
-        * @return void
-        */
-       public function testApiFriendicaGroupShow()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_lists_destroy() function.
-        *
-        * @return void
-        */
-       public function testApiListsDestroy()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the group_create() function.
-        *
-        * @return void
-        */
-       public function testGroupCreate()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_friendica_group_create() function.
-        *
-        * @return void
-        */
-       public function testApiFriendicaGroupCreate()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_lists_create() function.
-        *
-        * @return void
-        */
-       public function testApiListsCreate()
-       {
-               $this->markTestIncomplete();
-       }
-
-       /**
-        * Test the api_lists_update() function.
-        *
-        * @return void
-        */
-       public function testApiListsUpdate()
-       {
-               $this->markTestIncomplete();
-       }
 }