From 546ee038af8bd0fcd4f7b9ba1ba0417a506c2962 Mon Sep 17 00:00:00 2001
From: Philipp <admin@philipp.info>
Date: Sat, 15 Jan 2022 22:27:40 +0100
Subject: [PATCH 01/27] Bump smarty/smarty from 3.1.40 to 3.1.43

---
 composer.lock | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/composer.lock b/composer.lock
index 97bea93ec5..c0e14fe525 100644
--- a/composer.lock
+++ b/composer.lock
@@ -3647,16 +3647,16 @@
         },
         {
             "name": "smarty/smarty",
-            "version": "v3.1.40",
+            "version": "v3.1.43",
             "source": {
                 "type": "git",
                 "url": "https://github.com/smarty-php/smarty.git",
-                "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d"
+                "reference": "273f7e00fec034f6d61112552e9caf08d19565b7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d",
-                "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d",
+                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/273f7e00fec034f6d61112552e9caf08d19565b7",
+                "reference": "273f7e00fec034f6d61112552e9caf08d19565b7",
                 "shasum": ""
             },
             "require": {
@@ -3700,7 +3700,7 @@
             "keywords": [
                 "templating"
             ],
-            "time": "2021-10-13T10:04:31+00:00"
+            "time": "2022-01-10T09:52:40+00:00"
         },
         {
             "name": "spomky-labs/base64url",

From 95f085b7acdad95fbf8381554f4551a9cbf9409c Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sat, 15 Jan 2022 21:38:19 +0000
Subject: [PATCH 02/27] API: The legacy API finally moved

---
 include/api.php                               | 857 ------------------
 src/Content/Text/BBCode.php                   |   2 +-
 src/DI.php                                    |  16 +
 src/Factory/Api/Friendica/Group.php           |  59 ++
 src/Factory/Api/Friendica/Photo.php           | 154 ++++
 src/Module/Api/Friendica/Group/Create.php     |  87 ++
 src/Module/Api/Friendica/Group/Show.php       |  81 ++
 src/Module/Api/Friendica/Photo.php            |  49 +
 src/Module/Api/Friendica/Photo/Create.php     |  82 ++
 src/Module/Api/Friendica/Photo/Lists.php      |  66 ++
 src/Module/Api/Friendica/Photo/Update.php     | 136 +++
 .../Twitter/Account/UpdateProfileImage.php    |  72 ++
 src/Module/Api/Twitter/Lists/Create.php       |  66 ++
 src/Module/Api/Twitter/Lists/Destroy.php      |  64 ++
 .../Index.php => Twitter/Lists/Lists.php}     |  29 +-
 src/Module/Api/Twitter/Lists/Ownership.php    |  51 ++
 src/Module/Api/Twitter/Lists/Update.php       |  65 ++
 src/Object/Api/Friendica/Group.php            |  59 ++
 src/Util/Images.php                           |  24 +
 src/Util/ParseUrl.php                         |   1 +
 static/routes.config.php                      |  34 +-
 tests/legacy/ApiTest.php                      | 498 ----------
 22 files changed, 1161 insertions(+), 1391 deletions(-)
 delete mode 100644 include/api.php
 create mode 100644 src/Factory/Api/Friendica/Group.php
 create mode 100644 src/Factory/Api/Friendica/Photo.php
 create mode 100644 src/Module/Api/Friendica/Group/Create.php
 create mode 100644 src/Module/Api/Friendica/Group/Show.php
 create mode 100644 src/Module/Api/Friendica/Photo.php
 create mode 100644 src/Module/Api/Friendica/Photo/Create.php
 create mode 100644 src/Module/Api/Friendica/Photo/Lists.php
 create mode 100644 src/Module/Api/Friendica/Photo/Update.php
 create mode 100644 src/Module/Api/Twitter/Account/UpdateProfileImage.php
 create mode 100644 src/Module/Api/Twitter/Lists/Create.php
 create mode 100644 src/Module/Api/Twitter/Lists/Destroy.php
 rename src/Module/Api/{Friendica/Index.php => Twitter/Lists/Lists.php} (63%)
 create mode 100644 src/Module/Api/Twitter/Lists/Ownership.php
 create mode 100644 src/Module/Api/Twitter/Lists/Update.php
 create mode 100644 src/Object/Api/Friendica/Group.php

diff --git a/include/api.php b/include/api.php
deleted file mode 100644
index 9e8b3dd336..0000000000
--- a/include/api.php
+++ /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);
diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php
index a3244aafc3..1f638c2f52 100644
--- a/src/Content/Text/BBCode.php
+++ b/src/Content/Text/BBCode.php
@@ -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:
diff --git a/src/DI.php b/src/DI.php
index 89b102afc3..992e2c649d 100644
--- a/src/DI.php
+++ b/src/DI.php
@@ -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
index 0000000000..945971c285
--- /dev/null
+++ b/src/Factory/Api/Friendica/Group.php
@@ -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
index 0000000000..2a2f2be22f
--- /dev/null
+++ b/src/Factory/Api/Friendica/Photo.php
@@ -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
index 0000000000..85445588be
--- /dev/null
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -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
index 0000000000..62e13e08b6
--- /dev/null
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -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/Photo.php b/src/Module/Api/Friendica/Photo.php
new file mode 100644
index 0000000000..a27abb371d
--- /dev/null
+++ b/src/Module/Api/Friendica/Photo.php
@@ -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
index 0000000000..fe99a175d2
--- /dev/null
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -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
index 0000000000..826e32d085
--- /dev/null
+++ b/src/Module/Api/Friendica/Photo/Lists.php
@@ -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
index 0000000000..2b489bad35
--- /dev/null
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -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
index 0000000000..15ca6cf929
--- /dev/null
+++ b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
@@ -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
index 0000000000..f39d7bbfcb
--- /dev/null
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -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
index 0000000000..8e84cb8d4a
--- /dev/null
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -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/Friendica/Index.php b/src/Module/Api/Twitter/Lists/Lists.php
similarity index 63%
rename from src/Module/Api/Friendica/Index.php
rename to src/Module/Api/Twitter/Lists/Lists.php
index c3eeda23bc..09d740bb68 100644
--- a/src/Module/Api/Friendica/Index.php
+++ b/src/Module/Api/Twitter/Lists/Lists.php
@@ -19,32 +19,25 @@
  *
  */
 
-namespace Friendica\Module\Api\Friendica;
+namespace Friendica\Module\Api\Twitter\Lists;
 
-use Friendica\DI;
 use Friendica\Module\BaseApi;
-require_once __DIR__ . '/../../../../include/api.php';
+use Friendica\Model\Contact;
 
 /**
- * api/friendica
+ * Returns all lists the user subscribes to.
  *
- * @package Friendica\Module\Api\Friendica
+ * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
  */
-class Index extends BaseApi
+class Lists extends BaseApi
 {
-	protected function post(array $request = [])
-	{
-		self::checkAllowedScope(self::SCOPE_WRITE);		
-	}
-
-	protected function delete(array $request = [])
-	{
-		self::checkAllowedScope(self::SCOPE_WRITE);
-	}
-
 	protected function rawContent(array $request = [])
 	{
-		echo api_call(DI::args()->getCommand(), $this->parameters['extension'] ?? 'json');
-		exit();
+		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
+		$uid = BaseApi::getCurrentUserID();
+
+		// This is a dummy endpoint
+		$ret = [];
+		$this->response->exit('statuses', ["lists_list" => $ret], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 	}
 }
diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php
new file mode 100644
index 0000000000..57aa2855f2
--- /dev/null
+++ b/src/Module/Api/Twitter/Lists/Ownership.php
@@ -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
index 0000000000..e78ae2744d
--- /dev/null
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -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
index 0000000000..36dd6df6c9
--- /dev/null
+++ b/src/Object/Api/Friendica/Group.php
@@ -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';
+	}
+}
diff --git a/src/Util/Images.php b/src/Util/Images.php
index cd4704dcee..077509d3cb 100644
--- a/src/Util/Images.php
+++ b/src/Util/Images.php
@@ -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
 	 *
diff --git a/src/Util/ParseUrl.php b/src/Util/ParseUrl.php
index c1fcff28e6..04afc927ba 100644
--- a/src/Util/ParseUrl.php
+++ b/src/Util/ParseUrl.php
@@ -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;
 		}
 
diff --git a/static/routes.config.php b/static/routes.config.php
index 63c968c6c7..758462ca03 100644
--- a/static/routes.config.php
+++ b/static/routes.config.php
@@ -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]],
diff --git a/tests/legacy/ApiTest.php b/tests/legacy/ApiTest.php
index 075459d0ec..597f432ff7 100644
--- a/tests/legacy/ApiTest.php
+++ b/tests/legacy/ApiTest.php
@@ -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();
-	}
 }

From f68c94db04255eca8168c7608e82ad3d31b3dd55 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sat, 15 Jan 2022 21:45:08 +0000
Subject: [PATCH 03/27] Some standards

---
 src/Factory/Api/Friendica/Photo.php       | 21 +++++++++++----------
 src/Module/Api/Friendica/Photo.php        |  8 ++++----
 src/Module/Api/Friendica/Photo/Create.php |  6 +++---
 src/Module/Api/Friendica/Photo/Lists.php  |  6 +++---
 src/Module/Api/Friendica/Photo/Update.php |  8 ++++----
 5 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/src/Factory/Api/Friendica/Photo.php b/src/Factory/Api/Friendica/Photo.php
index 2a2f2be22f..85470c8806 100644
--- a/src/Factory/Api/Friendica/Photo.php
+++ b/src/Factory/Api/Friendica/Photo.php
@@ -59,12 +59,13 @@ class Photo extends BaseFactory
 	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'];
+			'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;
 		}
 
@@ -72,7 +73,7 @@ class Photo extends BaseFactory
 		if (empty($photos)) {
 			throw new HTTPException\NotFoundException();
 		}
-		$data = $photos[0];
+		$data       = $photos[0];
 		$data['id'] = $data['resource-id'];
 		if (is_int($scale)) {
 			$data['data'] = base64_encode(ModelPhoto::getImageDataForPhoto($data));
@@ -103,7 +104,7 @@ class Photo extends BaseFactory
 		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];
@@ -111,20 +112,20 @@ class Photo extends BaseFactory
 		}
 		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;
@@ -137,7 +138,7 @@ class Photo extends BaseFactory
 				}
 			}
 			$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'] ||
@@ -148,7 +149,7 @@ class Photo extends BaseFactory
 			$data['friendica_comments']   = [];
 			$data['rights_mismatch'] = false;
 		}
-	
+
 		return $data;
 	}
 }
\ No newline at end of file
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
index a27abb371d..5c2f46fc22 100644
--- a/src/Module/Api/Friendica/Photo.php
+++ b/src/Module/Api/Friendica/Photo.php
@@ -26,7 +26,7 @@ use Friendica\Model\Contact;
 use Friendica\Module\BaseApi;
 use Friendica\Network\HTTPException;
 
-class Activity extends BaseApi
+class Photo extends BaseApi
 {
 	protected function post(array $request = [])
 	{
@@ -37,13 +37,13 @@ class Activity extends BaseApi
 		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
index fe99a175d2..8da6acbf4e 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -45,19 +45,19 @@ class Create extends BaseApi
 		$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);
diff --git a/src/Module/Api/Friendica/Photo/Lists.php b/src/Module/Api/Friendica/Photo/Lists.php
index 826e32d085..d7080b4428 100644
--- a/src/Module/Api/Friendica/Photo/Lists.php
+++ b/src/Module/Api/Friendica/Photo/Lists.php
@@ -42,15 +42,15 @@ class Lists extends BaseApi
 
 		$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']);
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index 2b489bad35..c4bd6c70bf 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -37,7 +37,7 @@ class Update extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid  = BaseApi::getCurrentUserID();
 		$type = $this->parameters['extension'] ?? '';
-	
+
 		// input params
 		$photo_id  = $_REQUEST['photo_id']  ?? null;
 		$desc      = $_REQUEST['desc']      ?? null;
@@ -47,7 +47,7 @@ class Update extends BaseApi
 		$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) {
@@ -58,7 +58,7 @@ class Update extends BaseApi
 		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);
@@ -68,7 +68,7 @@ class Update extends BaseApi
 		if ($acl_input_error) {
 			throw new HTTPException\BadRequestException('acl data invalid');
 		}
-	
+
 		$updated_fields = [];
 
 		if (!is_null($desc)) {

From c55c42b303846c63841ce982ef485fac9904d0da Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 07:07:46 +0000
Subject: [PATCH 04/27] "DI" calls are replaced

---
 src/DI.php                                 | 24 ---------------
 src/Factory/Api/Friendica/Activities.php   |  6 +---
 src/Module/Api/Friendica/Photo.php         | 22 ++++++++++++--
 src/Module/Api/Friendica/Photo/Create.php  | 22 ++++++++++++--
 src/Module/Api/Friendica/Photo/Lists.php   | 20 +++++++++++--
 src/Module/Api/Friendica/Photo/Update.php  | 22 ++++++++++++--
 src/Module/Api/Twitter/Lists/Create.php    | 27 ++++++++++++++---
 src/Module/Api/Twitter/Lists/Destroy.php   | 27 ++++++++++++++---
 src/Module/Api/Twitter/Lists/Ownership.php | 26 ++++++++++++++---
 src/Module/Api/Twitter/Lists/Statuses.php  | 34 +++++++++++++++++-----
 src/Module/Api/Twitter/Lists/Update.php    | 27 ++++++++++++++---
 11 files changed, 194 insertions(+), 63 deletions(-)

diff --git a/src/DI.php b/src/DI.php
index 992e2c649d..708fb7d836 100644
--- a/src/DI.php
+++ b/src/DI.php
@@ -262,30 +262,6 @@ abstract class DI
 	// "Factory" namespace instances
 	//
 
-	/**
-	 * @return Factory\Api\Friendica\Activities
-	 */
-	public static function friendicaActivities()
-	{
-		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/Activities.php b/src/Factory/Api/Friendica/Activities.php
index b4936f3107..7b8f458b04 100644
--- a/src/Factory/Api/Friendica/Activities.php
+++ b/src/Factory/Api/Friendica/Activities.php
@@ -21,7 +21,6 @@
 
 namespace Friendica\Factory\Api\Friendica;
 
-use Friendica\App\BaseURL;
 use Friendica\BaseFactory;
 use Friendica\Database\DBA;
 use Friendica\Model\Post;
@@ -32,17 +31,14 @@ use Friendica\Factory\Api\Twitter\User as TwitterUser;
 
 class Activities extends BaseFactory
 {
-	/** @var BaseURL */
-	private $baseUrl;
 	/** @var twitterUser entity */
 	private $twitterUser;
 
-	public function __construct(LoggerInterface $logger, BaseURL $baseURL, TwitterUser $twitteruser)
+	public function __construct(LoggerInterface $logger, TwitterUser $twitteruser)
 	{
 		parent::__construct($logger);
 
 		$this->twitterUser = $twitteruser;
-		$this->baseUrl     = $baseURL;
 	}
 
 	/**
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
index 5c2f46fc22..4334bafebe 100644
--- a/src/Module/Api/Friendica/Photo.php
+++ b/src/Module/Api/Friendica/Photo.php
@@ -21,13 +21,29 @@
 
 namespace Friendica\Module\Api\Friendica;
 
-use Friendica\DI;
-use Friendica\Model\Contact;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
 use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 class Photo extends BaseApi
 {
+	/** @var FriendicaPhoto */
+	private $friendicaPhoto;
+
+
+	public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->friendicaPhoto = $friendicaPhoto;
+	}
+
 	protected function post(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
@@ -42,7 +58,7 @@ class Photo extends BaseApi
 		$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)];
+		$data = ['photo' => $this->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
index 8da6acbf4e..0455321d08 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -21,17 +21,33 @@
 
 namespace Friendica\Module\Api\Friendica\Photo;
 
+use Friendica\App;
 use Friendica\Core\ACL;
-use Friendica\DI;
-use Friendica\Model\Photo;
+use Friendica\Core\L10n;
+use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
 use Friendica\Module\BaseApi;
+use Friendica\Model\Photo;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * API endpoint: /api/friendica/photo/create
  */
 class Create extends BaseApi
 {
+	/** @var FriendicaPhoto */
+	private $friendicaPhoto;
+
+
+	public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->friendicaPhoto = $friendicaPhoto;
+	}
+
 	protected function post(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@@ -72,7 +88,7 @@ class Create extends BaseApi
 
 		// return success of updating or error message
 		if (!empty($photo)) {
-			$data = ['photo' => DI::friendicaPhoto()->createFromId($photo['resource_id'], null, $uid, $type)];
+			$data = ['photo' => $this->friendicaPhoto->createFromId($photo['resource_id'], null, $uid, $type)];
 			$this->response->exit('photo_create', $data, $this->parameters['extension'] ?? null);
 			return;
 		} else {
diff --git a/src/Module/Api/Friendica/Photo/Lists.php b/src/Module/Api/Friendica/Photo/Lists.php
index d7080b4428..6d2eb1716c 100644
--- a/src/Module/Api/Friendica/Photo/Lists.php
+++ b/src/Module/Api/Friendica/Photo/Lists.php
@@ -22,10 +22,15 @@
 namespace Friendica\Module\Api\Friendica\Photo;
 
 use Friendica\Database\DBA;
-use Friendica\DI;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
 use Friendica\Module\BaseApi;
 use Friendica\Model\Contact;
 use Friendica\Model\Photo;
+use Friendica\Module\Api\ApiResponse;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Returns all lists the user subscribes to.
@@ -34,6 +39,17 @@ use Friendica\Model\Photo;
  */
 class Lists extends BaseApi
 {
+	/** @var FriendicaPhoto */
+	private $friendicaPhoto;
+
+
+	public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->friendicaPhoto = $friendicaPhoto;
+	}
+
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
@@ -46,7 +62,7 @@ class Lists extends BaseApi
 		$data = ['photo' => []];
 		if (DBA::isResult($photos)) {
 			foreach ($photos as $photo) {
-				$element = DI::friendicaPhoto()->createFromId($photo['resource-id'], null, $uid, 'json', false);
+				$element = $this->friendicaPhoto->createFromId($photo['resource-id'], null, $uid, 'json', false);
 
 				$element['thumb'] = end($element['link']);
 				unset($element['link']);
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index c4bd6c70bf..b964ad0230 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -21,17 +21,33 @@
 
 namespace Friendica\Module\Api\Friendica\Photo;
 
+use Friendica\App;
 use Friendica\Core\ACL;
-use Friendica\DI;
-use Friendica\Model\Photo;
+use Friendica\Core\L10n;
+use Friendica\Factory\Api\Friendica\Photo as FriendicaPhoto;
 use Friendica\Module\BaseApi;
+use Friendica\Model\Photo;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * API endpoint: /api/friendica/photo/update
  */
 class Update extends BaseApi
 {
+	/** @var FriendicaPhoto */
+	private $friendicaPhoto;
+
+
+	public function __construct(FriendicaPhoto $friendicaPhoto, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->friendicaPhoto = $friendicaPhoto;
+	}
+
 	protected function post(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@@ -111,7 +127,7 @@ class Update extends BaseApi
 			$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)];
+				$data = ['photo' => $this->friendicaPhoto->createFromId($photo['resource_id'], null, $uid, $type)];
 				$this->response->exit('photo_update', $data, $this->parameters['extension'] ?? null);
 				return;
 			}
diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
index f39d7bbfcb..746f71d0f3 100644
--- a/src/Module/Api/Twitter/Lists/Create.php
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -21,12 +21,17 @@
 
 namespace Friendica\Module\Api\Twitter\Lists;
 
-use Friendica\Database\DBA;
-use Friendica\DI;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Database\Database;
+use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
 use Friendica\Module\BaseApi;
 use Friendica\Model\Contact;
 use Friendica\Model\Group;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Update information about a group.
@@ -35,6 +40,20 @@ use Friendica\Network\HTTPException;
  */
 class Create extends BaseApi
 {
+	/** @var friendicaGroup */
+	private $friendicaGroup;
+
+	/** @var Database */
+	private $dba;
+
+	public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->dba = $dba;
+		$this->friendicaGroup = $friendicaGroup;
+	}
+	
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@@ -48,7 +67,7 @@ class Create extends BaseApi
 		}
 	
 		// error message if specified group name already exists
-		if (DBA::exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) {
+		if ($this->dba->exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) {
 			throw new HTTPException\BadRequestException('group name already exists');
 		}
 	
@@ -59,7 +78,7 @@ class Create extends BaseApi
 			throw new HTTPException\BadRequestException('other API error');
 		}
 	
-		$grp = DI::friendicaGroup()->createFromId($gid);
+		$grp = $this->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
index 8e84cb8d4a..ee2ac2d3cb 100644
--- a/src/Module/Api/Twitter/Lists/Destroy.php
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -21,12 +21,17 @@
 
 namespace Friendica\Module\Api\Twitter\Lists;
 
-use Friendica\Database\DBA;
-use Friendica\DI;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Database\Database;
+use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
 use Friendica\Module\BaseApi;
 use Friendica\Model\Contact;
 use Friendica\Model\Group;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Delete a group.
@@ -35,6 +40,20 @@ use Friendica\Network\HTTPException;
  */
 class Destroy extends BaseApi
 {
+	/** @var friendicaGroup */
+	private $friendicaGroup;
+
+	/** @var Database */
+	private $dba;
+
+	public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->dba = $dba;
+		$this->friendicaGroup = $friendicaGroup;
+	}
+	
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@@ -49,13 +68,13 @@ class Destroy extends BaseApi
 		}
 	
 		// get data of the specified group id
-		$group = DBA::selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
+		$group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
 		// error message if specified gid is not in database
 		if (!$group) {
 			throw new HTTPException\BadRequestException('gid not available');
 		}
 	
-		$list = DI::friendicaGroup()->createFromId($gid);
+		$list = $this->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/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php
index 57aa2855f2..436097970d 100644
--- a/src/Module/Api/Twitter/Lists/Ownership.php
+++ b/src/Module/Api/Twitter/Lists/Ownership.php
@@ -21,10 +21,15 @@
 
 namespace Friendica\Module\Api\Twitter\Lists;
 
-use Friendica\Database\DBA;
-use Friendica\DI;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Database\Database;
+use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
 use Friendica\Module\BaseApi;
 use Friendica\Model\Contact;
+use Friendica\Module\Api\ApiResponse;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Returns all groups the user owns.
@@ -33,17 +38,30 @@ use Friendica\Model\Contact;
  */
 class Ownership extends BaseApi
 {
+	/** @var friendicaGroup */
+	private $friendicaGroup;
+
+	/** @var Database */
+	private $dba;
+
+	public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->dba = $dba;
+		$this->friendicaGroup = $friendicaGroup;
+	}
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 	
-		$groups = DBA::select('group', [], ['deleted' => false, 'uid' => $uid]);
+		$groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid]);
 	
 		// loop through all groups
 		$lists = [];
 		foreach ($groups as $group) {
-			$lists[] = DI::friendicaGroup()->createFromId($group['id']);
+			$lists[] = $this->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/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 34220fe993..257d6bc513 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -21,12 +21,18 @@
 
 namespace Friendica\Module\Api\Twitter\Lists;
 
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Database\Database;
 use Friendica\Database\DBA;
+use Friendica\Factory\Api\Twitter\Status as TwitterStatus;
 use Friendica\Module\BaseApi;
-use Friendica\DI;
 use Friendica\Model\Contact;
 use Friendica\Model\Post;
-use Friendica\Network\HTTPException\BadRequestException;
+use Friendica\Module\Api\ApiResponse;
+use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Returns recent statuses from users in the specified group.
@@ -35,13 +41,27 @@ use Friendica\Network\HTTPException\BadRequestException;
  */
 class Statuses extends BaseApi
 {
+	/** @var TwitterStatus */
+	private $twitterStatus;
+
+	/** @var Database */
+	private $dba;
+
+	public function __construct(Database $dba, TwitterStatus $twitterStatus, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->dba = $dba;
+		$this->twitterStatus = $twitterStatus;
+	}
+	
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
 		if (empty($request['list_id'])) {
-			throw new BadRequestException('list_id not specified');
+			throw new HTTPException\BadRequestException('list_id not specified');
 		}
 
 		// params
@@ -54,7 +74,7 @@ class Statuses extends BaseApi
 
 		$start = max(0, ($page - 1) * $count);
 
-		$groups    = DBA::selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]);
+		$groups    = $this->dba->selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]);
 		$gids      = array_column($groups, 'contact-id');
 		$condition = ['uid' => $uid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'contact-id' => $gids];
 		$condition = DBA::mergeConditions($condition, ["`id` > ?", $since_id]);
@@ -78,10 +98,10 @@ class Statuses extends BaseApi
 		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
 
 		$items = [];
-		while ($status = DBA::fetch($statuses)) {
-			$items[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
+		while ($status = $this->dba->fetch($statuses)) {
+			$items[] = $this->twitterStatus->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
 		}
-		DBA::close($statuses);
+		$this->dba->close($statuses);
 
 		$this->response->exit('statuses', ['status' => $items], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 	}
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
index e78ae2744d..95fe90d0ac 100644
--- a/src/Module/Api/Twitter/Lists/Update.php
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -21,12 +21,17 @@
 
 namespace Friendica\Module\Api\Twitter\Lists;
 
-use Friendica\Database\DBA;
-use Friendica\DI;
+use Friendica\App;
+use Friendica\Core\L10n;
+use Friendica\Database\Database;
+use Friendica\Factory\Api\Friendica\Group as FriendicaGroup;
 use Friendica\Module\BaseApi;
 use Friendica\Model\Contact;
 use Friendica\Model\Group;
+use Friendica\Module\Api\ApiResponse;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
 
 /**
  * Update information about a group.
@@ -35,6 +40,20 @@ use Friendica\Network\HTTPException;
  */
 class Update extends BaseApi
 {
+	/** @var friendicaGroup */
+	private $friendicaGroup;
+
+	/** @var Database */
+	private $dba;
+
+	public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
+	{
+		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+		$this->dba = $dba;
+		$this->friendicaGroup = $friendicaGroup;
+	}
+
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@@ -50,14 +69,14 @@ class Update extends BaseApi
 		}
 	
 		// get data of the specified group id
-		$group = DBA::selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
+		$group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
 		// error message if specified gid is not in database
 		if (!$group) {
 			throw new HTTPException\BadRequestException('gid not available');
 		}
 	
 		if (Group::update($gid, $name)) {
-			$list = DI::friendicaGroup()->createFromId($gid);
+			$list = $this->friendicaGroup->createFromId($gid);
 	
 			$this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 		}

From 8ff2cc397653da8243b5dac4238af317d348220d Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 07:14:09 +0000
Subject: [PATCH 05/27] Superflous spaces

---
 src/Module/Api/Friendica/Group/Create.php  | 18 +++++++++---------
 src/Module/Api/Friendica/Group/Delete.php  |  1 -
 src/Module/Api/Friendica/Group/Show.php    | 10 +++++-----
 src/Module/Api/Twitter/Lists/Create.php    | 14 +++++++-------
 src/Module/Api/Twitter/Lists/Destroy.php   | 12 ++++++------
 src/Module/Api/Twitter/Lists/Ownership.php |  4 ++--
 src/Module/Api/Twitter/Lists/Statuses.php  |  2 +-
 src/Module/Api/Twitter/Lists/Update.php    | 10 +++++-----
 8 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Group/Create.php
index 85445588be..be85146f4d 100644
--- a/src/Module/Api/Friendica/Group/Create.php
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -35,27 +35,27 @@ class Create extends BaseApi
 	{
 		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) {
@@ -63,7 +63,7 @@ class Create extends BaseApi
 		} else {
 			throw new HTTPException\BadRequestException('other API error');
 		}
-	
+
 		// add members
 		$erroraddinguser = false;
 		$errorusers = [];
@@ -76,12 +76,12 @@ class Create extends BaseApi
 				$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/Delete.php b/src/Module/Api/Friendica/Group/Delete.php
index e845bd7a73..d48e9a4f9d 100644
--- a/src/Module/Api/Friendica/Group/Delete.php
+++ b/src/Module/Api/Friendica/Group/Delete.php
@@ -22,7 +22,6 @@
 namespace Friendica\Module\Api\Friendica\Group;
 
 use Friendica\Database\DBA;
-use Friendica\DI;
 use Friendica\Model\Group;
 use Friendica\Module\BaseApi;
 use Friendica\Network\HTTPException\BadRequestException;
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index 62e13e08b6..3ec2b76254 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -37,14 +37,14 @@ class Show extends BaseApi
 		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');
@@ -52,13 +52,13 @@ class Show extends BaseApi
 		} 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;
diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
index 746f71d0f3..80071c30e2 100644
--- a/src/Module/Api/Twitter/Lists/Create.php
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -53,33 +53,33 @@ class Create extends BaseApi
 		$this->dba = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
-	
+
 	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 ($this->dba->exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) {
 			throw new HTTPException\BadRequestException('group name already exists');
 		}
-	
+
 		$ret = Group::create($uid, $name);
 		if ($ret) {
 			$gid = Group::getIdByName($uid, $name);
 		} else {
 			throw new HTTPException\BadRequestException('other API error');
 		}
-	
+
 		$grp = $this->friendicaGroup->createFromId($gid);
-	
+
 		$this->response->exit('statuses', ['lists' => ['lists' => $grp]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 	}
 }
diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php
index ee2ac2d3cb..06ca9a73dc 100644
--- a/src/Module/Api/Twitter/Lists/Destroy.php
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -53,29 +53,29 @@ class Destroy extends BaseApi
 		$this->dba = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
-	
+
 	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 = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
 		// error message if specified gid is not in database
 		if (!$group) {
 			throw new HTTPException\BadRequestException('gid not available');
 		}
-	
+
 		$list = $this->friendicaGroup->createFromId($gid);
-	
+
 		if (Group::remove($gid)) {
 			$this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 		}
diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php
index 436097970d..e94a078231 100644
--- a/src/Module/Api/Twitter/Lists/Ownership.php
+++ b/src/Module/Api/Twitter/Lists/Ownership.php
@@ -55,9 +55,9 @@ class Ownership extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
-	
+
 		$groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid]);
-	
+
 		// loop through all groups
 		$lists = [];
 		foreach ($groups as $group) {
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 257d6bc513..5da93740a0 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -54,7 +54,7 @@ class Statuses extends BaseApi
 		$this->dba = $dba;
 		$this->twitterStatus = $twitterStatus;
 	}
-	
+
 	protected function rawContent(array $request = [])
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
index 95fe90d0ac..d670c3a6d4 100644
--- a/src/Module/Api/Twitter/Lists/Update.php
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -58,26 +58,26 @@ class Update extends BaseApi
 	{
 		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 = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
 		// error message if specified gid is not in database
 		if (!$group) {
 			throw new HTTPException\BadRequestException('gid not available');
 		}
-	
+
 		if (Group::update($gid, $name)) {
 			$list = $this->friendicaGroup->createFromId($gid);
-	
+
 			$this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
 		}
 	}

From f11bf08a7ba18bd5d76d38891bea0e7dd52edc96 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 07:35:20 +0000
Subject: [PATCH 06/27] Use the $request variable

---
 src/Module/Api/Friendica/Group/Create.php        |  2 +-
 src/Module/Api/Friendica/Group/Show.php          |  2 +-
 src/Module/Api/Friendica/Notification/Seen.php   |  4 ++--
 src/Module/Api/Friendica/Photo.php               |  6 +++---
 src/Module/Api/Friendica/Photo/Create.php        | 12 ++++++------
 src/Module/Api/Friendica/Photo/Update.php        | 16 ++++++++--------
 .../Api/Twitter/Account/UpdateProfileImage.php   |  2 +-
 src/Module/Api/Twitter/Friendships/Show.php      |  4 ++--
 src/Module/Api/Twitter/Lists/Create.php          |  2 +-
 src/Module/Api/Twitter/Lists/Destroy.php         |  2 +-
 src/Module/Api/Twitter/Lists/Update.php          |  4 ++--
 11 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Group/Create.php
index be85146f4d..15394fec42 100644
--- a/src/Module/Api/Friendica/Group/Create.php
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -37,7 +37,7 @@ class Create extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$name = $_REQUEST['name'] ?? '';
+		$name = $request['name'] ?? '';
 		$json = json_decode($_POST['json'], true);
 		$users = $json['user'];
 
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index 3ec2b76254..b2ce4ea065 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -39,7 +39,7 @@ class Show extends BaseApi
 		$type = $this->parameters['extension'] ?? '';
 
 		// params
-		$gid = $_REQUEST['gid'] ?? 0;
+		$gid = $request['gid'] ?? 0;
 
 		// get data of the specified group id or all groups if not specified
 		if ($gid != 0) {
diff --git a/src/Module/Api/Friendica/Notification/Seen.php b/src/Module/Api/Friendica/Notification/Seen.php
index e293372624..30637d78c1 100644
--- a/src/Module/Api/Friendica/Notification/Seen.php
+++ b/src/Module/Api/Friendica/Notification/Seen.php
@@ -47,7 +47,7 @@ class Seen extends BaseApi
 			throw new BadRequestException('Invalid argument count');
 		}
 
-		$id = intval($_REQUEST['id'] ?? 0);
+		$id = intval($request['id'] ?? 0);
 
 		try {
 			$Notify = DI::notify()->selectOneById($id);
@@ -65,7 +65,7 @@ class Seen extends BaseApi
 			if ($Notify->otype === Notification\ObjectType::ITEM) {
 				$item = Post::selectFirstForUser($uid, [], ['id' => $Notify->iid, 'uid' => $uid]);
 				if (DBA::isResult($item)) {
-					$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+					$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
 
 					// we found the item, return it to the user
 					$ret  = [DI::twitterStatus()->createFromUriId($item['uri-id'], $item['uid'], $include_entities)->toArray()];
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
index 4334bafebe..6e5b02c4fd 100644
--- a/src/Module/Api/Friendica/Photo.php
+++ b/src/Module/Api/Friendica/Photo.php
@@ -50,12 +50,12 @@ class Photo extends BaseApi
 		$uid  = BaseApi::getCurrentUserID();
 		$type = $this->parameters['extension'] ?? '';
 
-		if (empty($_REQUEST['photo_id'])) {
+		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'];
+		$scale = (!empty($request['scale']) ? intval($request['scale']) : false);
+		$photo_id = $request['photo_id'];
 
 		// prepare json/xml output with data from database for the requested photo
 		$data = ['photo' => $this->friendicaPhoto->createFromId($photo_id, $scale, $uid, $type)];
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
index 0455321d08..460bff40f9 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -55,12 +55,12 @@ class Create extends BaseApi
 		$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;
+		$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
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index b964ad0230..24c07be8e6 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -55,14 +55,14 @@ class Update extends BaseApi
 		$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;
+		$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
diff --git a/src/Module/Api/Twitter/Account/UpdateProfileImage.php b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
index 15ca6cf929..422ed4416c 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfileImage.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
@@ -57,7 +57,7 @@ class UpdateProfileImage extends BaseApi
 		}
 	
 		// output for client
-		$skip_status = $_REQUEST['skip_status'] ?? false;
+		$skip_status = $request['skip_status'] ?? false;
 	
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 	
diff --git a/src/Module/Api/Twitter/Friendships/Show.php b/src/Module/Api/Twitter/Friendships/Show.php
index 6db48506a3..66605e7265 100644
--- a/src/Module/Api/Twitter/Friendships/Show.php
+++ b/src/Module/Api/Twitter/Friendships/Show.php
@@ -38,9 +38,9 @@ class Show extends ContactEndpoint
 		self::checkAllowedScope(self::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		$source_cid = BaseApi::getContactIDForSearchterm($_REQUEST['source_screen_name'] ?? '', '', $_REQUEST['source_id'] ?? 0, $uid);
+		$source_cid = BaseApi::getContactIDForSearchterm($request['source_screen_name'] ?? '', '', $request['source_id'] ?? 0, $uid);
 
-		$target_cid = BaseApi::getContactIDForSearchterm($_REQUEST['target_screen_name'] ?? '', '', $_REQUEST['target_id'] ?? 0, $uid);
+		$target_cid = BaseApi::getContactIDForSearchterm($request['target_screen_name'] ?? '', '', $request['target_id'] ?? 0, $uid);
 
 		$source = Contact::getById($source_cid);
 		if (empty($source)) {
diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
index 80071c30e2..cbe1503855 100644
--- a/src/Module/Api/Twitter/Lists/Create.php
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -60,7 +60,7 @@ class Create extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$name = $_REQUEST['name'] ?? '';
+		$name = $request['name'] ?? '';
 
 		if ($name == '') {
 			throw new HTTPException\BadRequestException('group name not specified');
diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php
index 06ca9a73dc..c0377e135b 100644
--- a/src/Module/Api/Twitter/Lists/Destroy.php
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -60,7 +60,7 @@ class Destroy extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$gid = $_REQUEST['list_id'] ?? 0;
+		$gid = $request['list_id'] ?? 0;
 
 		// error if no gid specified
 		if ($gid == 0) {
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
index d670c3a6d4..ba3886aaaf 100644
--- a/src/Module/Api/Twitter/Lists/Update.php
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -60,8 +60,8 @@ class Update extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$gid  = $_REQUEST['list_id'] ?? 0;
-		$name = $_REQUEST['name'] ?? '';
+		$gid  = $request['list_id'] ?? 0;
+		$name = $request['name'] ?? '';
 
 		// error if no gid specified
 		if ($gid == 0) {

From af18e2f2a9ef9315e0767ee395a745f17760a460 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 07:41:26 +0000
Subject: [PATCH 07/27] $_POST replaced

---
 src/Module/Api/Friendica/Group/Create.php | 2 +-
 src/Module/Api/Friendica/Group/Update.php | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Group/Create.php
index 15394fec42..c57a20143a 100644
--- a/src/Module/Api/Friendica/Group/Create.php
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -38,7 +38,7 @@ class Create extends BaseApi
 
 		// params
 		$name = $request['name'] ?? '';
-		$json = json_decode($_POST['json'], true);
+		$json = json_decode($request['json'], true);
 		$users = $json['user'];
 
 		// error if no name specified
diff --git a/src/Module/Api/Friendica/Group/Update.php b/src/Module/Api/Friendica/Group/Update.php
index b17e29c1bf..5b18af236b 100644
--- a/src/Module/Api/Friendica/Group/Update.php
+++ b/src/Module/Api/Friendica/Group/Update.php
@@ -40,7 +40,7 @@ class Update extends BaseApi
 		// params
 		$gid   = $request['gid']  ?? 0;
 		$name  = $request['name'] ?? '';
-		$json  = json_decode($_POST['json'], true);
+		$json  = json_decode($request['json'], true);
 		$users = $json['user'];
 
 		// error if no name specified

From 7c15d0160a75936bed78cf9680cbb31db7074baf Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 09:01:04 +0000
Subject: [PATCH 08/27] Coding styles / "require_once" for removed file removed

---
 src/Factory/Api/Friendica/Photo.php                   |  2 +-
 src/Module/Api/Friendica/Group/Create.php             |  8 ++++----
 src/Module/Api/Friendica/Group/Show.php               | 10 ++++------
 src/Module/Api/Friendica/Photo.php                    |  2 +-
 src/Module/Api/Friendica/Photo/Update.php             |  4 ++--
 src/Module/Api/Twitter/Account/UpdateProfileImage.php |  2 +-
 tests/legacy/ApiTest.php                              |  2 --
 7 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/src/Factory/Api/Friendica/Photo.php b/src/Factory/Api/Friendica/Photo.php
index 85470c8806..9c0a48dea7 100644
--- a/src/Factory/Api/Friendica/Photo.php
+++ b/src/Factory/Api/Friendica/Photo.php
@@ -152,4 +152,4 @@ class Photo extends BaseFactory
 
 		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
index c57a20143a..2742bae8c6 100644
--- a/src/Module/Api/Friendica/Group/Create.php
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -37,8 +37,8 @@ class Create extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$name = $request['name'] ?? '';
-		$json = json_decode($request['json'], true);
+		$name  = $request['name'] ?? '';
+		$json  = json_decode($request['json'], true);
 		$users = $json['user'];
 
 		// error if no name specified
@@ -66,14 +66,14 @@ class Create extends BaseApi
 
 		// add members
 		$erroraddinguser = false;
-		$errorusers = [];
+		$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;
+				$errorusers[]    = $cid;
 			}
 		}
 
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index b2ce4ea065..f735e7c116 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -57,20 +57,18 @@ class Show extends BaseApi
 		$grps = [];
 		foreach ($groups as $rr) {
 			$members = Contact\Group::getById($rr['id']);
-			$users = [];
+			$users   = [];
 
 			if ($type == 'xml') {
 				$user_element = 'users';
-				$k = 0;
+				$k            = 0;
 				foreach ($members as $member) {
-					$user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
-					$users[$k++.':user'] = $user;
+					$users[$k++.':user'] = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
 				}
 			} else {
 				$user_element = 'user';
 				foreach ($members as $member) {
-					$user = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
-					$users[] = $user;
+					$users[] = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray();
 				}
 			}
 			$grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users];
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
index 6e5b02c4fd..d0ea25b309 100644
--- a/src/Module/Api/Friendica/Photo.php
+++ b/src/Module/Api/Friendica/Photo.php
@@ -54,7 +54,7 @@ class Photo extends BaseApi
 			throw new HTTPException\BadRequestException('No photo id.');
 		}
 
-		$scale = (!empty($request['scale']) ? intval($request['scale']) : false);
+		$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
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index 24c07be8e6..a7ac91460e 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -118,14 +118,14 @@ class Update extends BaseApi
 		$result = false;
 		if (count($updated_fields) > 0) {
 			$nothingtodo = false;
-			$result = Photo::update($updated_fields, ['uid' => $uid, 'resource-id' => $photo_id, 'album' => $album]);
+			$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);
+			$photo       = Photo::upload($uid, $_FILES['media'], $album, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc, $photo_id);
 			if (!empty($photo)) {
 				$data = ['photo' => $this->friendicaPhoto->createFromId($photo['resource_id'], null, $uid, $type)];
 				$this->response->exit('photo_update', $data, $this->parameters['extension'] ?? null);
diff --git a/src/Module/Api/Twitter/Account/UpdateProfileImage.php b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
index 422ed4416c..909c4c29e7 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfileImage.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
@@ -57,7 +57,7 @@ class UpdateProfileImage extends BaseApi
 		}
 	
 		// output for client
-		$skip_status = $request['skip_status'] ?? false;
+		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
 	
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 	
diff --git a/tests/legacy/ApiTest.php b/tests/legacy/ApiTest.php
index 597f432ff7..904ae92f6c 100644
--- a/tests/legacy/ApiTest.php
+++ b/tests/legacy/ApiTest.php
@@ -32,8 +32,6 @@ use Friendica\Util\Arrays;
 use Friendica\Util\DateTimeFormat;
 use Monolog\Handler\TestHandler;
 
-require_once __DIR__ . '/../../include/api.php';
-
 /**
  * Tests for the API functions.
  *

From e6108668e3f6fdc4b1b4fc070acac4846aebafde Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 09:07:39 +0000
Subject: [PATCH 09/27] Some more cidong style

---
 src/Module/Api/Twitter/Lists/Create.php    | 2 +-
 src/Module/Api/Twitter/Lists/Destroy.php   | 2 +-
 src/Module/Api/Twitter/Lists/Ownership.php | 2 +-
 src/Module/Api/Twitter/Lists/Statuses.php  | 2 +-
 src/Module/Api/Twitter/Lists/Update.php    | 2 +-
 view/lang/C/messages.po                    | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
index cbe1503855..799f01a4c7 100644
--- a/src/Module/Api/Twitter/Lists/Create.php
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -50,7 +50,7 @@ class Create extends BaseApi
 	{
 		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
-		$this->dba = $dba;
+		$this->dba            = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
 
diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php
index c0377e135b..2bb9642df0 100644
--- a/src/Module/Api/Twitter/Lists/Destroy.php
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -50,7 +50,7 @@ class Destroy extends BaseApi
 	{
 		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
-		$this->dba = $dba;
+		$this->dba            = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
 
diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php
index e94a078231..e5aca1ad5c 100644
--- a/src/Module/Api/Twitter/Lists/Ownership.php
+++ b/src/Module/Api/Twitter/Lists/Ownership.php
@@ -48,7 +48,7 @@ class Ownership extends BaseApi
 	{
 		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
-		$this->dba = $dba;
+		$this->dba            = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
 	protected function rawContent(array $request = [])
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 5da93740a0..68afa411e4 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -51,7 +51,7 @@ class Statuses extends BaseApi
 	{
 		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
-		$this->dba = $dba;
+		$this->dba           = $dba;
 		$this->twitterStatus = $twitterStatus;
 	}
 
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
index ba3886aaaf..34a0b658ff 100644
--- a/src/Module/Api/Twitter/Lists/Update.php
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -50,7 +50,7 @@ class Update extends BaseApi
 	{
 		parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
-		$this->dba = $dba;
+		$this->dba            = $dba;
 		$this->friendicaGroup = $friendicaGroup;
 	}
 
diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po
index 7860e4b4bb..9273287808 100644
--- a/view/lang/C/messages.po
+++ b/view/lang/C/messages.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: 2021.12-rc\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-01-12 21:28+0000\n"
+"POT-Creation-Date: 2022-01-16 08:58+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"

From 7b68a5956e831fdb32d99b6840654dc050cf3c63 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 09:24:35 +0000
Subject: [PATCH 10/27] Improved handling of boolean input values

---
 src/Module/Api/Friendica/Notification/Seen.php       |  2 +-
 src/Module/Api/GNUSocial/Statusnet/Conversation.php  | 12 ++++++------
 src/Module/Api/Twitter/Account/UpdateProfile.php     |  2 +-
 src/Module/Api/Twitter/Account/VerifyCredentials.php |  2 +-
 src/Module/Api/Twitter/Lists/Statuses.php            |  2 +-
 src/Module/Api/Twitter/Search/Tweets.php             |  2 +-
 src/Module/Api/Twitter/Statuses/Destroy.php          |  2 +-
 src/Module/Api/Twitter/Statuses/HomeTimeline.php     |  2 +-
 src/Module/Api/Twitter/Statuses/Mentions.php         |  2 +-
 .../Api/Twitter/Statuses/NetworkPublicTimeline.php   |  2 +-
 src/Module/Api/Twitter/Statuses/PublicTimeline.php   |  2 +-
 src/Module/Api/Twitter/Statuses/Show.php             |  2 +-
 src/Module/Api/Twitter/Statuses/UserTimeline.php     |  2 +-
 13 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/Module/Api/Friendica/Notification/Seen.php b/src/Module/Api/Friendica/Notification/Seen.php
index 30637d78c1..7b37b7615f 100644
--- a/src/Module/Api/Friendica/Notification/Seen.php
+++ b/src/Module/Api/Friendica/Notification/Seen.php
@@ -65,7 +65,7 @@ class Seen extends BaseApi
 			if ($Notify->otype === Notification\ObjectType::ITEM) {
 				$item = Post::selectFirstForUser($uid, [], ['id' => $Notify->iid, 'uid' => $uid]);
 				if (DBA::isResult($item)) {
-					$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
+					$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 					// we found the item, return it to the user
 					$ret  = [DI::twitterStatus()->createFromUriId($item['uri-id'], $item['uid'], $include_entities)->toArray()];
diff --git a/src/Module/Api/GNUSocial/Statusnet/Conversation.php b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
index 76bc9b8165..cd70cb5022 100644
--- a/src/Module/Api/GNUSocial/Statusnet/Conversation.php
+++ b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
@@ -41,15 +41,15 @@ class Conversation extends BaseApi
 
 		// params
 		$id       = $this->parameters['id'] ?? 0;
-		$since_id = $_REQUEST['since_id']   ?? 0;
-		$max_id   = $_REQUEST['max_id']     ?? 0;
-		$count    = $_REQUEST['count']      ?? 20;
-		$page     = $_REQUEST['page']       ?? 1;
+		$since_id = $request['since_id']    ?? 0;
+		$max_id   = $request['max_id']      ?? 0;
+		$count    = $request['count']       ?? 20;
+		$page     = $request['page']        ?? 1;
 
 		$start = max(0, ($page - 1) * $count);
 
 		if ($id == 0) {
-			$id = $_REQUEST['id'] ?? 0;
+			$id = $request['id'] ?? 0;
 		}
 
 		Logger::info(BaseApi::LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
@@ -82,7 +82,7 @@ class Conversation extends BaseApi
 			throw new BadRequestException("There is no status with id $id.");
 		}
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Account/UpdateProfile.php b/src/Module/Api/Twitter/Account/UpdateProfile.php
index 079d58f4be..70cac42a27 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfile.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfile.php
@@ -56,7 +56,7 @@ class UpdateProfile extends BaseApi
 
 		Profile::publishUpdate($uid);
 
-		$skip_status = $request['skip_status'] ?? false;
+		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 
diff --git a/src/Module/Api/Twitter/Account/VerifyCredentials.php b/src/Module/Api/Twitter/Account/VerifyCredentials.php
index 592cff4c0c..181c20dfb7 100644
--- a/src/Module/Api/Twitter/Account/VerifyCredentials.php
+++ b/src/Module/Api/Twitter/Account/VerifyCredentials.php
@@ -37,7 +37,7 @@ class VerifyCredentials extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		$skip_status = $_REQUEST['skip_status'] ?? false;
+		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 68afa411e4..301966a6a4 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -95,7 +95,7 @@ class Statuses extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$items = [];
 		while ($status = $this->dba->fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Search/Tweets.php b/src/Module/Api/Twitter/Search/Tweets.php
index 759c797a6e..c8ebd21db4 100644
--- a/src/Module/Api/Twitter/Search/Tweets.php
+++ b/src/Module/Api/Twitter/Search/Tweets.php
@@ -115,7 +115,7 @@ class Tweets extends BaseApi
 
 		$statuses = $statuses ?: Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/Destroy.php b/src/Module/Api/Twitter/Statuses/Destroy.php
index 784b8ef66f..aabf6f98db 100644
--- a/src/Module/Api/Twitter/Statuses/Destroy.php
+++ b/src/Module/Api/Twitter/Statuses/Destroy.php
@@ -50,7 +50,7 @@ class Destroy extends BaseApi
 
 		$this->logger->notice('API: api_statuses_destroy: ' . $id);
 
-		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = DI::twitterStatus()->createFromItemId($id, $uid, $include_entities)->toArray();
 
diff --git a/src/Module/Api/Twitter/Statuses/HomeTimeline.php b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
index a9ed6a832b..8a54aeda63 100644
--- a/src/Module/Api/Twitter/Statuses/HomeTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
@@ -71,7 +71,7 @@ class HomeTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret     = [];
 		$idarray = [];
diff --git a/src/Module/Api/Twitter/Statuses/Mentions.php b/src/Module/Api/Twitter/Statuses/Mentions.php
index 31cde911eb..cb66a49f1b 100644
--- a/src/Module/Api/Twitter/Statuses/Mentions.php
+++ b/src/Module/Api/Twitter/Statuses/Mentions.php
@@ -72,7 +72,7 @@ class Mentions extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php b/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
index 5fa104e88f..d7612d193a 100644
--- a/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
@@ -58,7 +58,7 @@ class NetworkPublicTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, Item::DISPLAY_FIELDLIST, $condition, $params);
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/PublicTimeline.php b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
index 0015d3e08d..5508d3b09f 100644
--- a/src/Module/Api/Twitter/Statuses/PublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
@@ -78,7 +78,7 @@ class PublicTimeline extends BaseApi
 			$statuses = Post::selectForUser($uid, [], $condition, $params);
 		}
 
-		$include_entities = strtolower(($_REQUEST['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/Show.php b/src/Module/Api/Twitter/Statuses/Show.php
index d037697518..f698997094 100644
--- a/src/Module/Api/Twitter/Statuses/Show.php
+++ b/src/Module/Api/Twitter/Statuses/Show.php
@@ -79,7 +79,7 @@ class Show extends BaseApi
 			throw new BadRequestException(sprintf("There is no status or conversation with the id %d.", $id));
 		}
 
-		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/UserTimeline.php b/src/Module/Api/Twitter/Statuses/UserTimeline.php
index 2c884a6b6c..2255287c77 100644
--- a/src/Module/Api/Twitter/Statuses/UserTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/UserTimeline.php
@@ -74,7 +74,7 @@ class UserTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
+		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {

From 4319136421ceee3ddc65bab8d3908d32974ee86b Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 12:38:04 +0000
Subject: [PATCH 11/27] Improved defaults check

---
 src/BaseModule.php | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/BaseModule.php b/src/BaseModule.php
index 5ac56533ca..06d9da66af 100644
--- a/src/BaseModule.php
+++ b/src/BaseModule.php
@@ -261,15 +261,15 @@ abstract class BaseModule implements ICanHandleRequests
 
 		foreach ($defaults as $parameter => $defaultvalue) {
 			if (is_string($defaultvalue)) {
-				$request[$parameter] = $input[$parameter] ?? $defaultvalue;
+				$request[$parameter] = (string)($input[$parameter] ?? $defaultvalue);
 			} elseif (is_int($defaultvalue)) {
-				$request[$parameter] = (int)($input[$parameter] ?? $defaultvalue);
+				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_INT);
 			} elseif (is_float($defaultvalue)) {
-				$request[$parameter] = (float)($input[$parameter] ?? $defaultvalue);
+				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_FLOAT);
 			} elseif (is_array($defaultvalue)) {
-				$request[$parameter] = $input[$parameter] ?? [];
+				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_DEFAULT, ['flags' => FILTER_FORCE_ARRAY]);
 			} elseif (is_bool($defaultvalue)) {
-				$request[$parameter] = in_array(strtolower($input[$parameter] ?? ''), ['true', '1']);
+				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_BOOLEAN);
 			} else {
 				$this->logger->notice('Unhandled default value type', ['parameter' => $parameter, 'type' => gettype($defaultvalue)]);
 			}

From 4724000d06cd47bd5eee97111f2723962007d3dc Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 14:04:20 +0000
Subject: [PATCH 12/27] Unify request value handling

---
 src/BaseModule.php                            | 58 ++++++++++++++-----
 src/Module/Api/Friendica/Group/Create.php     |  2 +-
 src/Module/Api/Friendica/Group/Show.php       |  2 +-
 src/Module/Api/Friendica/Group/Update.php     |  4 +-
 src/Module/Api/Friendica/Photo/Create.php     | 14 ++---
 src/Module/Api/Friendica/Photo/Update.php     | 16 ++---
 .../Api/GNUSocial/Statusnet/Conversation.php  |  8 +--
 .../Api/Twitter/DirectMessagesEndpoint.php    | 12 ++--
 src/Module/Api/Twitter/Favorites.php          |  8 +--
 src/Module/Api/Twitter/Lists/Create.php       |  2 +-
 src/Module/Api/Twitter/Lists/Destroy.php      |  2 +-
 src/Module/Api/Twitter/Lists/Statuses.php     | 14 ++---
 src/Module/Api/Twitter/Lists/Update.php       |  4 +-
 .../Api/Twitter/Statuses/HomeTimeline.php     | 12 ++--
 src/Module/Api/Twitter/Statuses/Mentions.php  |  8 +--
 .../Api/Twitter/Statuses/PublicTimeline.php   | 12 ++--
 16 files changed, 105 insertions(+), 73 deletions(-)

diff --git a/src/BaseModule.php b/src/BaseModule.php
index 06d9da66af..d85e895a17 100644
--- a/src/BaseModule.php
+++ b/src/BaseModule.php
@@ -260,19 +260,7 @@ abstract class BaseModule implements ICanHandleRequests
 		$request = [];
 
 		foreach ($defaults as $parameter => $defaultvalue) {
-			if (is_string($defaultvalue)) {
-				$request[$parameter] = (string)($input[$parameter] ?? $defaultvalue);
-			} elseif (is_int($defaultvalue)) {
-				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_INT);
-			} elseif (is_float($defaultvalue)) {
-				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_FLOAT);
-			} elseif (is_array($defaultvalue)) {
-				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_DEFAULT, ['flags' => FILTER_FORCE_ARRAY]);
-			} elseif (is_bool($defaultvalue)) {
-				$request[$parameter] = filter_var($input[$parameter] ?? $defaultvalue, FILTER_VALIDATE_BOOLEAN);
-			} else {
-				$this->logger->notice('Unhandled default value type', ['parameter' => $parameter, 'type' => gettype($defaultvalue)]);
-			}
+			$request[$parameter] = $this->getRequestValue($input, $parameter, $defaultvalue);
 		}
 
 		foreach ($input ?? [] as $parameter => $value) {
@@ -288,6 +276,50 @@ abstract class BaseModule implements ICanHandleRequests
 		return $request;
 	}
 
+	/**
+	 * Fetch a request value and apply default values and check against minimal and maximal values
+	 *
+	 * @param array $input 
+	 * @param string $parameter 
+	 * @param mixed $default 
+	 * @param mixed $minimal_value 
+	 * @param mixed $maximum_value 
+	 * @return mixed 
+	 */
+	public function getRequestValue(array $input, string $parameter, $default = null, $minimal_value = null, $maximum_value = null)
+	{
+		if (is_string($default)) {
+			$value = (string)($input[$parameter] ?? $default);
+		} elseif (is_int($default)) {
+			$value = filter_var($input[$parameter] ?? $default, FILTER_VALIDATE_INT);
+			if (!is_null($minimal_value)) {
+				$value = max(filter_var($minimal_value, FILTER_VALIDATE_INT), $value);
+			}
+			if (!is_null($maximum_value)) {
+				$value = min(filter_var($minimal_value, FILTER_VALIDATE_INT), $value);
+			}
+		} elseif (is_float($default)) {
+			$value = filter_var($input[$parameter] ?? $default, FILTER_VALIDATE_FLOAT);
+			if (!is_null($minimal_value)) {
+				$value = max(filter_var($minimal_value, FILTER_VALIDATE_FLOAT), $value);
+			}
+			if (!is_null($maximum_value)) {
+				$value = min(filter_var($minimal_value, FILTER_VALIDATE_FLOAT), $value);
+			}
+		} elseif (is_array($default)) {
+			$value = filter_var($input[$parameter] ?? $default, FILTER_DEFAULT, ['flags' => FILTER_FORCE_ARRAY]);
+		} elseif (is_bool($default)) {
+			$value = filter_var($input[$parameter] ?? $default, FILTER_VALIDATE_BOOLEAN);
+		} elseif (is_null($default)) {
+			$value = $input[$parameter] ?? null;
+		} else {
+			$this->logger->notice('Unhandled default value type', ['parameter' => $parameter, 'type' => gettype($default)]);
+			$value = null;
+		}
+
+		return $value;
+	}
+
 	/*
 	 * Functions used to protect against Cross-Site Request Forgery
 	 * The security token has to base on at least one value that an attacker can't know - here it's the session ID and the private key.
diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Group/Create.php
index 2742bae8c6..3b0f030135 100644
--- a/src/Module/Api/Friendica/Group/Create.php
+++ b/src/Module/Api/Friendica/Group/Create.php
@@ -37,7 +37,7 @@ class Create extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$name  = $request['name'] ?? '';
+		$name  = $this->getRequestValue($request, 'name', '');
 		$json  = json_decode($request['json'], true);
 		$users = $json['user'];
 
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index f735e7c116..ec0bdd1348 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -39,7 +39,7 @@ class Show extends BaseApi
 		$type = $this->parameters['extension'] ?? '';
 
 		// params
-		$gid = $request['gid'] ?? 0;
+		$gid = $this->getRequestValue($request, 'gid', 0);
 
 		// get data of the specified group id or all groups if not specified
 		if ($gid != 0) {
diff --git a/src/Module/Api/Friendica/Group/Update.php b/src/Module/Api/Friendica/Group/Update.php
index 5b18af236b..defbeed1c1 100644
--- a/src/Module/Api/Friendica/Group/Update.php
+++ b/src/Module/Api/Friendica/Group/Update.php
@@ -38,8 +38,8 @@ class Update extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$gid   = $request['gid']  ?? 0;
-		$name  = $request['name'] ?? '';
+		$gid   = $this->getRequestValue($request, 'gid', 0);
+		$name  = $this->getRequestValue($request, 'name', '');
 		$json  = json_decode($request['json'], true);
 		$users = $json['user'];
 
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
index 460bff40f9..0eeb455140 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -54,13 +54,13 @@ class Create extends BaseApi
 		$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;
+		// input params	
+		$desc      = $this->getRequestValue($request, 'desc');
+		$album     = $this->getRequestValue($request, 'album');
+		$allow_cid = $this->getRequestValue($request, 'allow_cid');
+		$deny_cid  = $this->getRequestValue($request, 'deny_cid');
+		$allow_gid = $this->getRequestValue($request, 'allow_gid');
+		$deny_gid  = $this->getRequestValue($request, 'deny_gid');
 
 		// do several checks on input parameters
 		// we do not allow calls without album string
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index a7ac91460e..ccb9f91503 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -55,14 +55,14 @@ class Update extends BaseApi
 		$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;
+		$photo_id  = $this->getRequestValue($request, 'photo_id');
+		$desc      = $this->getRequestValue($request, 'desc');
+		$album     = $this->getRequestValue($request, 'album');
+		$album_new = $this->getRequestValue($request, 'album_new');
+		$allow_cid = $this->getRequestValue($request, 'allow_cid');
+		$deny_cid  = $this->getRequestValue($request, 'deny_cid');
+		$allow_gid = $this->getRequestValue($request, 'allow_gid');
+		$deny_gid  = $this->getRequestValue($request, 'deny_gid');
 
 		// do several checks on input parameters
 		// we do not allow calls without album string
diff --git a/src/Module/Api/GNUSocial/Statusnet/Conversation.php b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
index cd70cb5022..77fdc034ba 100644
--- a/src/Module/Api/GNUSocial/Statusnet/Conversation.php
+++ b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
@@ -41,10 +41,10 @@ class Conversation extends BaseApi
 
 		// params
 		$id       = $this->parameters['id'] ?? 0;
-		$since_id = $request['since_id']    ?? 0;
-		$max_id   = $request['max_id']      ?? 0;
-		$count    = $request['count']       ?? 20;
-		$page     = $request['page']        ?? 1;
+		$since_id = $this->getRequestValue($request, 'since_id', 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0);
+		$count    = $this->getRequestValue($request, 'count', 20);
+		$page     = $this->getRequestValue($request, 'page', 1);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/DirectMessagesEndpoint.php b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
index c88e43036a..a1f519975c 100644
--- a/src/Module/Api/Twitter/DirectMessagesEndpoint.php
+++ b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
@@ -58,12 +58,12 @@ abstract class DirectMessagesEndpoint extends BaseApi
 	protected function getMessages(array $request, int $uid, array $condition)
 	{
 		// params
-		$count    = filter_var($request['count'] ?? 20,                FILTER_VALIDATE_INT, ['options' => ['max_range' => 100]]);
-		$page     = filter_var($request['page'] ?? 1,                  FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
-		$since_id = filter_var($request['since_id'] ?? 0,              FILTER_VALIDATE_INT);
-		$max_id   = filter_var($request['max_id'] ?? 0,                FILTER_VALIDATE_INT);
-		$min_id   = filter_var($request['min_id'] ?? 0,                FILTER_VALIDATE_INT);
-		$verbose  = filter_var($request['friendica_verbose'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page     = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 1);
+		$verbose  = $this->getRequestValue($request, 'friendica_verbose', false);
 
 		// pagination
 		$start = max(0, ($page - 1) * $count);
diff --git a/src/Module/Api/Twitter/Favorites.php b/src/Module/Api/Twitter/Favorites.php
index 9a7149cab7..56aa26cda7 100644
--- a/src/Module/Api/Twitter/Favorites.php
+++ b/src/Module/Api/Twitter/Favorites.php
@@ -45,10 +45,10 @@ class Favorites extends BaseApi
 		Logger::info(BaseApi::LOG_PREFIX . 'for {self}', ['module' => 'api', 'action' => 'favorites']);
 
 		// params
-		$since_id = $request['since_id'] ?? 0;
-		$max_id   = $request['max_id']   ?? 0;
-		$count    = $request['count']    ?? 20;
-		$page     = $request['page']     ?? 1;
+		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page     = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php
index 799f01a4c7..26e94eb1ab 100644
--- a/src/Module/Api/Twitter/Lists/Create.php
+++ b/src/Module/Api/Twitter/Lists/Create.php
@@ -60,7 +60,7 @@ class Create extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$name = $request['name'] ?? '';
+		$name = $this->getRequestValue($request, 'name', '');
 
 		if ($name == '') {
 			throw new HTTPException\BadRequestException('group name not specified');
diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php
index 2bb9642df0..8390bab775 100644
--- a/src/Module/Api/Twitter/Lists/Destroy.php
+++ b/src/Module/Api/Twitter/Lists/Destroy.php
@@ -60,7 +60,7 @@ class Destroy extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$gid = $request['list_id'] ?? 0;
+		$gid = $this->getRequestValue($request, 'list_id', 0);
 
 		// error if no gid specified
 		if ($gid == 0) {
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 301966a6a4..268ad81941 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -65,12 +65,12 @@ class Statuses extends BaseApi
 		}
 
 		// params
-		$count           = $request['count']    ?? 20;
-		$page            = $request['page']     ?? 1;
-		$since_id        = $request['since_id'] ?? 0;
-		$max_id          = $request['max_id']   ?? 0;
-		$exclude_replies = (!empty($request['exclude_replies']) ? 1 : 0);
-		$conversation_id = $request['conversation_id'] ?? 0;
+		$count           = $this->getRequestValue($request, 'count', 20);
+		$page            = $this->getRequestValue($request, 'page', 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0);
+		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -83,7 +83,7 @@ class Statuses extends BaseApi
 			$condition[0] .= " AND `id` <= ?";
 			$condition[] = $max_id;
 		}
-		if ($exclude_replies > 0) {
+		if ($exclude_replies) {
 			$condition[0] .= ' AND `gravity` = ?';
 			$condition[] = GRAVITY_PARENT;
 		}
diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php
index 34a0b658ff..e7929e77d2 100644
--- a/src/Module/Api/Twitter/Lists/Update.php
+++ b/src/Module/Api/Twitter/Lists/Update.php
@@ -60,8 +60,8 @@ class Update extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$gid  = $request['list_id'] ?? 0;
-		$name = $request['name'] ?? '';
+		$gid  = $this->getRequestValue($request, 'list_id', 0);
+		$name = $this->getRequestValue($request, 'name', '');
 
 		// error if no gid specified
 		if ($gid == 0) {
diff --git a/src/Module/Api/Twitter/Statuses/HomeTimeline.php b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
index 8a54aeda63..c45342a523 100644
--- a/src/Module/Api/Twitter/Statuses/HomeTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
@@ -43,12 +43,12 @@ class HomeTimeline extends BaseApi
 		// get last network messages
 
 		// params
-		$count           = $_REQUEST['count']    ?? 20;
-		$page            = $_REQUEST['page']     ?? 0;
-		$since_id        = $_REQUEST['since_id'] ?? 0;
-		$max_id          = $_REQUEST['max_id']   ?? 0;
-		$exclude_replies = !empty($_REQUEST['exclude_replies']);
-		$conversation_id = $_REQUEST['conversation_id'] ?? 0;
+		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page            = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0, 1);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0, 1);
+		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Statuses/Mentions.php b/src/Module/Api/Twitter/Statuses/Mentions.php
index cb66a49f1b..954aca57b4 100644
--- a/src/Module/Api/Twitter/Statuses/Mentions.php
+++ b/src/Module/Api/Twitter/Statuses/Mentions.php
@@ -42,10 +42,10 @@ class Mentions extends BaseApi
 		// get last network messages
 
 		// params
-		$since_id = $_REQUEST['since_id'] ?? 0;
-		$max_id   = $_REQUEST['max_id']   ?? 0;
-		$count    = $_REQUEST['count']    ?? 20;
-		$page     = $_REQUEST['page']     ?? 1;
+		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page     = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Statuses/PublicTimeline.php b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
index 5508d3b09f..53950573be 100644
--- a/src/Module/Api/Twitter/Statuses/PublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
@@ -41,12 +41,12 @@ class PublicTimeline extends BaseApi
 		// get last network messages
 
 		// params
-		$count           = $_REQUEST['count']    ?? 20;
-		$page            = $_REQUEST['page']     ?? 1;
-		$since_id        = $_REQUEST['since_id'] ?? 0;
-		$max_id          = $_REQUEST['max_id']   ?? 0;
-		$exclude_replies = (!empty($_REQUEST['exclude_replies']) ? 1 : 0);
-		$conversation_id = $_REQUEST['conversation_id'] ?? 0;
+		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page            = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0, 1);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0, 1);
+		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
 
 		$start = max(0, ($page - 1) * $count);
 

From a3173ccb5074d0da75ecc76fd069fa328e2a9cc4 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 15:03:01 +0000
Subject: [PATCH 13/27] Define reasonable min and max values

---
 src/Module/Api/GNUSocial/Statusnet/Conversation.php |  8 ++++----
 src/Module/Api/Twitter/DirectMessagesEndpoint.php   |  6 +++---
 src/Module/Api/Twitter/Favorites.php                |  4 ++--
 src/Module/Api/Twitter/Lists/Statuses.php           | 10 +++++-----
 src/Module/Api/Twitter/Statuses/HomeTimeline.php    |  6 +++---
 src/Module/Api/Twitter/Statuses/Mentions.php        |  4 ++--
 src/Module/Api/Twitter/Statuses/PublicTimeline.php  |  6 +++---
 7 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/src/Module/Api/GNUSocial/Statusnet/Conversation.php b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
index 77fdc034ba..5edcc4099d 100644
--- a/src/Module/Api/GNUSocial/Statusnet/Conversation.php
+++ b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
@@ -41,10 +41,10 @@ class Conversation extends BaseApi
 
 		// params
 		$id       = $this->parameters['id'] ?? 0;
-		$since_id = $this->getRequestValue($request, 'since_id', 0);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0);
-		$count    = $this->getRequestValue($request, 'count', 20);
-		$page     = $this->getRequestValue($request, 'page', 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page     = $this->getRequestValue($request, 'page', 1, 1);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/DirectMessagesEndpoint.php b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
index a1f519975c..c0c271dd76 100644
--- a/src/Module/Api/Twitter/DirectMessagesEndpoint.php
+++ b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
@@ -60,9 +60,9 @@ abstract class DirectMessagesEndpoint extends BaseApi
 		// params
 		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$page     = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
-		$min_id   = $this->getRequestValue($request, 'min_id', 0, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 		$verbose  = $this->getRequestValue($request, 'friendica_verbose', false);
 
 		// pagination
diff --git a/src/Module/Api/Twitter/Favorites.php b/src/Module/Api/Twitter/Favorites.php
index 56aa26cda7..e88922af7d 100644
--- a/src/Module/Api/Twitter/Favorites.php
+++ b/src/Module/Api/Twitter/Favorites.php
@@ -47,8 +47,8 @@ class Favorites extends BaseApi
 		// params
 		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$page     = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 268ad81941..87cb1b4ebd 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -65,12 +65,12 @@ class Statuses extends BaseApi
 		}
 
 		// params
-		$count           = $this->getRequestValue($request, 'count', 20);
-		$page            = $this->getRequestValue($request, 'page', 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0);
+		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page            = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
 		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Statuses/HomeTimeline.php b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
index c45342a523..41ce9b37e1 100644
--- a/src/Module/Api/Twitter/Statuses/HomeTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
@@ -45,10 +45,10 @@ class HomeTimeline extends BaseApi
 		// params
 		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$page            = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0, 1);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0, 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
 		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Statuses/Mentions.php b/src/Module/Api/Twitter/Statuses/Mentions.php
index 954aca57b4..0ddabd9a4a 100644
--- a/src/Module/Api/Twitter/Statuses/Mentions.php
+++ b/src/Module/Api/Twitter/Statuses/Mentions.php
@@ -44,8 +44,8 @@ class Mentions extends BaseApi
 		// params
 		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$page     = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 1);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 1);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 
diff --git a/src/Module/Api/Twitter/Statuses/PublicTimeline.php b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
index 53950573be..2a71bfe965 100644
--- a/src/Module/Api/Twitter/Statuses/PublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
@@ -43,10 +43,10 @@ class PublicTimeline extends BaseApi
 		// params
 		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$page            = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0, 1);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0, 1);
+		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
 		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0);
+		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 

From 720a43461d67ab229de0aecfc5008f22cc4c1c54 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 15:22:35 +0000
Subject: [PATCH 14/27] Fixed max value check, improved request value fetching

---
 src/BaseModule.php                            |  4 ++--
 .../Api/Friendica/Notification/Seen.php       |  4 ++--
 .../Api/GNUSocial/Statusnet/Conversation.php  | 13 ++++++-------
 src/Module/Api/Twitter/Lists/Statuses.php     | 15 +++++++--------
 src/Module/Api/Twitter/Search/Tweets.php      |  4 ++--
 src/Module/Api/Twitter/Statuses/Destroy.php   |  3 +--
 .../Api/Twitter/Statuses/HomeTimeline.php     | 15 +++++++--------
 src/Module/Api/Twitter/Statuses/Mentions.php  | 11 +++++------
 .../Statuses/NetworkPublicTimeline.php        | 13 +++++--------
 .../Api/Twitter/Statuses/PublicTimeline.php   | 15 +++++++--------
 src/Module/Api/Twitter/Statuses/Show.php      |  2 +-
 .../Api/Twitter/Statuses/UserTimeline.php     | 19 ++++++++-----------
 12 files changed, 53 insertions(+), 65 deletions(-)

diff --git a/src/BaseModule.php b/src/BaseModule.php
index d85e895a17..c03a77e29e 100644
--- a/src/BaseModule.php
+++ b/src/BaseModule.php
@@ -296,7 +296,7 @@ abstract class BaseModule implements ICanHandleRequests
 				$value = max(filter_var($minimal_value, FILTER_VALIDATE_INT), $value);
 			}
 			if (!is_null($maximum_value)) {
-				$value = min(filter_var($minimal_value, FILTER_VALIDATE_INT), $value);
+				$value = min(filter_var($maximum_value, FILTER_VALIDATE_INT), $value);
 			}
 		} elseif (is_float($default)) {
 			$value = filter_var($input[$parameter] ?? $default, FILTER_VALIDATE_FLOAT);
@@ -304,7 +304,7 @@ abstract class BaseModule implements ICanHandleRequests
 				$value = max(filter_var($minimal_value, FILTER_VALIDATE_FLOAT), $value);
 			}
 			if (!is_null($maximum_value)) {
-				$value = min(filter_var($minimal_value, FILTER_VALIDATE_FLOAT), $value);
+				$value = min(filter_var($maximum_value, FILTER_VALIDATE_FLOAT), $value);
 			}
 		} elseif (is_array($default)) {
 			$value = filter_var($input[$parameter] ?? $default, FILTER_DEFAULT, ['flags' => FILTER_FORCE_ARRAY]);
diff --git a/src/Module/Api/Friendica/Notification/Seen.php b/src/Module/Api/Friendica/Notification/Seen.php
index 7b37b7615f..7a52a124df 100644
--- a/src/Module/Api/Friendica/Notification/Seen.php
+++ b/src/Module/Api/Friendica/Notification/Seen.php
@@ -49,6 +49,8 @@ class Seen extends BaseApi
 
 		$id = intval($request['id'] ?? 0);
 
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
+
 		try {
 			$Notify = DI::notify()->selectOneById($id);
 			if ($Notify->uid !== $uid) {
@@ -65,8 +67,6 @@ class Seen extends BaseApi
 			if ($Notify->otype === Notification\ObjectType::ITEM) {
 				$item = Post::selectFirstForUser($uid, [], ['id' => $Notify->iid, 'uid' => $uid]);
 				if (DBA::isResult($item)) {
-					$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 					// we found the item, return it to the user
 					$ret  = [DI::twitterStatus()->createFromUriId($item['uri-id'], $item['uid'], $include_entities)->toArray()];
 					$data = ['status' => $ret];
diff --git a/src/Module/Api/GNUSocial/Statusnet/Conversation.php b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
index 5edcc4099d..f21f4c3117 100644
--- a/src/Module/Api/GNUSocial/Statusnet/Conversation.php
+++ b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
@@ -40,11 +40,12 @@ class Conversation extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$id       = $this->parameters['id'] ?? 0;
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
-		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page     = $this->getRequestValue($request, 'page', 1, 1);
+		$id               = $this->parameters['id'] ?? 0;
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -82,8 +83,6 @@ class Conversation extends BaseApi
 			throw new BadRequestException("There is no status with id $id.");
 		}
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php
index 87cb1b4ebd..2bf27697b4 100644
--- a/src/Module/Api/Twitter/Lists/Statuses.php
+++ b/src/Module/Api/Twitter/Lists/Statuses.php
@@ -65,12 +65,13 @@ class Statuses extends BaseApi
 		}
 
 		// params
-		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page            = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
-		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$exclude_replies  = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id  = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -95,8 +96,6 @@ class Statuses extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$items = [];
 		while ($status = $this->dba->fetch($statuses)) {
 			$items[] = $this->twitterStatus->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Search/Tweets.php b/src/Module/Api/Twitter/Search/Tweets.php
index c8ebd21db4..0d6b5c2308 100644
--- a/src/Module/Api/Twitter/Search/Tweets.php
+++ b/src/Module/Api/Twitter/Search/Tweets.php
@@ -62,6 +62,8 @@ class Tweets extends BaseApi
 		$max_id   = $_REQUEST['max_id']   ?? 0;
 		$page     = $_REQUEST['page']     ?? 1;
 
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
+
 		$start = max(0, ($page - 1) * $count);
 
 		$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
@@ -115,8 +117,6 @@ class Tweets extends BaseApi
 
 		$statuses = $statuses ?: Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Statuses/Destroy.php b/src/Module/Api/Twitter/Statuses/Destroy.php
index aabf6f98db..7f4a6c6dc7 100644
--- a/src/Module/Api/Twitter/Statuses/Destroy.php
+++ b/src/Module/Api/Twitter/Statuses/Destroy.php
@@ -21,7 +21,6 @@
 
 namespace Friendica\Module\Api\Twitter\Statuses;
 
-use Friendica\Core\Logger;
 use Friendica\Module\BaseApi;
 use Friendica\DI;
 use Friendica\Model\Contact;
@@ -50,7 +49,7 @@ class Destroy extends BaseApi
 
 		$this->logger->notice('API: api_statuses_destroy: ' . $id);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$ret = DI::twitterStatus()->createFromItemId($id, $uid, $include_entities)->toArray();
 
diff --git a/src/Module/Api/Twitter/Statuses/HomeTimeline.php b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
index 41ce9b37e1..41314bb1b7 100644
--- a/src/Module/Api/Twitter/Statuses/HomeTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/HomeTimeline.php
@@ -43,12 +43,13 @@ class HomeTimeline extends BaseApi
 		// get last network messages
 
 		// params
-		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page            = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
-		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$exclude_replies  = $this->getRequestValue($request, 'exclude_replies', false);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
+		$conversation_id  = $this->getRequestValue($request, 'conversation_id', 0, 0);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -71,8 +72,6 @@ class HomeTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret     = [];
 		$idarray = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/Mentions.php b/src/Module/Api/Twitter/Statuses/Mentions.php
index 0ddabd9a4a..e9bbb93bdf 100644
--- a/src/Module/Api/Twitter/Statuses/Mentions.php
+++ b/src/Module/Api/Twitter/Statuses/Mentions.php
@@ -42,10 +42,11 @@ class Mentions extends BaseApi
 		// get last network messages
 
 		// params
-		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page     = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -72,8 +73,6 @@ class Mentions extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php b/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
index d7612d193a..af0436b4a2 100644
--- a/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/NetworkPublicTimeline.php
@@ -38,12 +38,11 @@ class NetworkPublicTimeline extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		$since_id = $_REQUEST['since_id'] ?? 0;
-		$max_id   = $_REQUEST['max_id']   ?? 0;
-
-		// pagination
-		$count = $_REQUEST['count'] ?? 20;
-		$page  = $_REQUEST['page']  ?? 1;
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -58,8 +57,6 @@ class NetworkPublicTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, Item::DISPLAY_FIELDLIST, $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Statuses/PublicTimeline.php b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
index 2a71bfe965..aba330a658 100644
--- a/src/Module/Api/Twitter/Statuses/PublicTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/PublicTimeline.php
@@ -41,12 +41,13 @@ class PublicTimeline extends BaseApi
 		// get last network messages
 
 		// params
-		$count           = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page            = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id        = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id          = $this->getRequestValue($request, 'max_id', 0, 0);
-		$exclude_replies = $this->getRequestValue($request, 'exclude_replies', false);
-		$conversation_id = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$exclude_replies  = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id  = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -78,8 +79,6 @@ class PublicTimeline extends BaseApi
 			$statuses = Post::selectForUser($uid, [], $condition, $params);
 		}
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Statuses/Show.php b/src/Module/Api/Twitter/Statuses/Show.php
index f698997094..a854837905 100644
--- a/src/Module/Api/Twitter/Statuses/Show.php
+++ b/src/Module/Api/Twitter/Statuses/Show.php
@@ -79,7 +79,7 @@ class Show extends BaseApi
 			throw new BadRequestException(sprintf("There is no status or conversation with the id %d.", $id));
 		}
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
diff --git a/src/Module/Api/Twitter/Statuses/UserTimeline.php b/src/Module/Api/Twitter/Statuses/UserTimeline.php
index 2255287c77..b6dcd86c91 100644
--- a/src/Module/Api/Twitter/Statuses/UserTimeline.php
+++ b/src/Module/Api/Twitter/Statuses/UserTimeline.php
@@ -42,15 +42,14 @@ class UserTimeline extends BaseApi
 
 		Logger::info('api_statuses_user_timeline', ['api_user' => $uid, '_REQUEST' => $request]);
 
-		$cid             = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
-		$since_id        = $request['since_id'] ?? 0;
-		$max_id          = $request['max_id']   ?? 0;
-		$exclude_replies = !empty($request['exclude_replies']);
-		$conversation_id = $request['conversation_id'] ?? 0;
-
-		// pagination
-		$count = $request['count'] ?? 20;
-		$page  = $request['page']  ?? 1;
+		$cid              = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$exclude_replies  = $this->getRequestValue($request, 'exclude_replies', false);
+		$conversation_id  = $this->getRequestValue($request, 'conversation_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -74,8 +73,6 @@ class UserTimeline extends BaseApi
 		$params   = ['order' => ['id' => true], 'limit' => [$start, $count]];
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = filter_var($request['include_entities'] ?? false, FILTER_VALIDATE_BOOLEAN);
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();

From 344d514857f0e18976ee6d88a891188b472c6273 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 16:40:13 +0000
Subject: [PATCH 15/27] Replaced "filter_input" with the new request value
 function

---
 .../Api/Twitter/Account/UpdateProfile.php     |  2 +-
 .../Twitter/Account/UpdateProfileImage.php    |  2 +-
 .../Api/Twitter/Account/VerifyCredentials.php |  2 +-
 src/Module/Api/Twitter/Blocks/Ids.php         | 17 ++++++-------
 src/Module/Api/Twitter/Blocks/Lists.php       | 19 ++++++--------
 .../Api/Twitter/DirectMessages/Destroy.php    |  4 +--
 src/Module/Api/Twitter/Followers/Ids.php      | 23 ++++++++---------
 src/Module/Api/Twitter/Followers/Lists.php    | 25 ++++++++-----------
 src/Module/Api/Twitter/Friends/Ids.php        | 23 ++++++++---------
 src/Module/Api/Twitter/Friends/Lists.php      | 25 ++++++++-----------
 .../Api/Twitter/Friendships/Incoming.php      | 17 ++++++-------
 11 files changed, 69 insertions(+), 90 deletions(-)

diff --git a/src/Module/Api/Twitter/Account/UpdateProfile.php b/src/Module/Api/Twitter/Account/UpdateProfile.php
index 70cac42a27..06ebf3db1e 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfile.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfile.php
@@ -56,7 +56,7 @@ class UpdateProfile extends BaseApi
 
 		Profile::publishUpdate($uid);
 
-		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$skip_status = $this->getRequestValue($request, 'skip_status', false);
 
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 
diff --git a/src/Module/Api/Twitter/Account/UpdateProfileImage.php b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
index 909c4c29e7..02194316b2 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfileImage.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
@@ -57,7 +57,7 @@ class UpdateProfileImage extends BaseApi
 		}
 	
 		// output for client
-		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$skip_status = $this->getRequestValue($request, 'skip_status', false);
 	
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 	
diff --git a/src/Module/Api/Twitter/Account/VerifyCredentials.php b/src/Module/Api/Twitter/Account/VerifyCredentials.php
index 181c20dfb7..af9c2a6f70 100644
--- a/src/Module/Api/Twitter/Account/VerifyCredentials.php
+++ b/src/Module/Api/Twitter/Account/VerifyCredentials.php
@@ -37,7 +37,7 @@ class VerifyCredentials extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		$skip_status = filter_var($request['skip_status'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$skip_status = $this->getRequestValue($request, 'skip_status', false);
 
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
 
diff --git a/src/Module/Api/Twitter/Blocks/Ids.php b/src/Module/Api/Twitter/Blocks/Ids.php
index e411fc507f..d687b85a5c 100644
--- a/src/Module/Api/Twitter/Blocks/Ids.php
+++ b/src/Module/Api/Twitter/Blocks/Ids.php
@@ -37,17 +37,14 @@ class Ids extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$cursor        = filter_input(INPUT_GET, 'cursor'       , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count         = filter_input(INPUT_GET, 'count'        , FILTER_VALIDATE_INT, ['options' => [
-			'default'   => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$cursor        = $this->getRequestValue($request, 'cursor', -1);
+		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
+		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
-		$max_id   = filter_input(INPUT_GET, 'max_id'  , FILTER_VALIDATE_INT);
-		$min_id   = filter_input(INPUT_GET, 'min_id'  , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$params = ['order' => ['cid' => true], 'limit' => $count];
 
diff --git a/src/Module/Api/Twitter/Blocks/Lists.php b/src/Module/Api/Twitter/Blocks/Lists.php
index da7b00f43c..823336c087 100644
--- a/src/Module/Api/Twitter/Blocks/Lists.php
+++ b/src/Module/Api/Twitter/Blocks/Lists.php
@@ -37,18 +37,15 @@ class Lists extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$cursor                = filter_input(INPUT_GET, 'cursor'               , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$skip_status           = filter_input(INPUT_GET, 'skip_status'          , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count                 = filter_input(INPUT_GET, 'count'                , FILTER_VALIDATE_INT, ['options' => [
-			'default'   => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$cursor                = $this->getRequestValue($request, 'cursor', -1);
+		$skip_status           = $this->getRequestValue($request, 'skip_status', false);
+		$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
+		$count                 = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
-		$max_id   = filter_input(INPUT_GET, 'max_id'  , FILTER_VALIDATE_INT);
-		$min_id   = filter_input(INPUT_GET, 'min_id'  , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$params = ['order' => ['cid' => true], 'limit' => $count];
 
diff --git a/src/Module/Api/Twitter/DirectMessages/Destroy.php b/src/Module/Api/Twitter/DirectMessages/Destroy.php
index 9f9c4de303..3100ff345e 100644
--- a/src/Module/Api/Twitter/DirectMessages/Destroy.php
+++ b/src/Module/Api/Twitter/DirectMessages/Destroy.php
@@ -52,8 +52,8 @@ class Destroy extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid = BaseApi::getCurrentUserID();
 
-		$id      = filter_var($request['id'] ?? 0,                    FILTER_VALIDATE_INT);
-		$verbose = filter_var($request['friendica_verbose'] ?? false, FILTER_VALIDATE_BOOLEAN);
+		$id      = $this->getRequestValue($request, 'id', 0);
+		$verbose = $this->getRequestValue($request, 'friendica_verbose', false);
 
 		$parenturi = $request['friendica_parenturi'] ?? '';
 
diff --git a/src/Module/Api/Twitter/Followers/Ids.php b/src/Module/Api/Twitter/Followers/Ids.php
index a618304b21..d03b547acd 100644
--- a/src/Module/Api/Twitter/Followers/Ids.php
+++ b/src/Module/Api/Twitter/Followers/Ids.php
@@ -37,20 +37,17 @@ class Ids extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id    = filter_input(INPUT_GET, 'user_id'      , FILTER_VALIDATE_INT);
-		$screen_name   = filter_input(INPUT_GET, 'screen_name');
-		$profile_url   = filter_input(INPUT_GET, 'profile_url');
-		$cursor        = filter_input(INPUT_GET, 'cursor'       , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count         = filter_input(INPUT_GET, 'count'        , FILTER_VALIDATE_INT, ['options' => [
-			'default' => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$contact_id    = $this->getRequestValue($request, 'user_id', 0);
+		$screen_name   = $this->getRequestValue($request, 'screen_name', '');
+		$profile_url   = $this->getRequestValue($request, 'profile_url', '');
+		$cursor        = $this->getRequestValue($request, 'cursor', -1);
+		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
+		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id      = filter_input(INPUT_GET, 'since_id'     , FILTER_VALIDATE_INT);
-		$max_id        = filter_input(INPUT_GET, 'max_id'       , FILTER_VALIDATE_INT);
-		$min_id        = filter_input(INPUT_GET, 'min_id'       , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
 
diff --git a/src/Module/Api/Twitter/Followers/Lists.php b/src/Module/Api/Twitter/Followers/Lists.php
index a60226d05f..0aca285a19 100644
--- a/src/Module/Api/Twitter/Followers/Lists.php
+++ b/src/Module/Api/Twitter/Followers/Lists.php
@@ -37,21 +37,18 @@ class Lists extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id            = filter_input(INPUT_GET, 'user_id'              , FILTER_VALIDATE_INT);
-		$screen_name           = filter_input(INPUT_GET, 'screen_name');
-		$profile_url           = filter_input(INPUT_GET, 'profile_url');
-		$cursor                = filter_input(INPUT_GET, 'cursor'               , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$skip_status           = filter_input(INPUT_GET, 'skip_status'          , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count                 = filter_input(INPUT_GET, 'count'                , FILTER_VALIDATE_INT, ['options' => [
-			'default' => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$contact_id            = $this->getRequestValue($request, 'user_id', 0);
+		$screen_name           = $this->getRequestValue($request, 'screen_name', '');
+		$profile_url           = $this->getRequestValue($request, 'profile_url', '');
+		$cursor                = $this->getRequestValue($request, 'cursor', -1);
+		$skip_status           = $this->getRequestValue($request, 'skip_status', false);
+		$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
+		$count                 = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id              = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
-		$max_id                = filter_input(INPUT_GET, 'max_id'  , FILTER_VALIDATE_INT);
-		$min_id                = filter_input(INPUT_GET, 'min_id'  , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
 
diff --git a/src/Module/Api/Twitter/Friends/Ids.php b/src/Module/Api/Twitter/Friends/Ids.php
index d810ceeb43..c874432e11 100644
--- a/src/Module/Api/Twitter/Friends/Ids.php
+++ b/src/Module/Api/Twitter/Friends/Ids.php
@@ -37,20 +37,17 @@ class Ids extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id    = filter_input(INPUT_GET, 'user_id'      , FILTER_VALIDATE_INT);
-		$screen_name   = filter_input(INPUT_GET, 'screen_name');
-		$profile_url   = filter_input(INPUT_GET, 'profile_url');
-		$cursor        = filter_input(INPUT_GET, 'cursor'       , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count         = filter_input(INPUT_GET, 'count'        , FILTER_VALIDATE_INT, ['options' => [
-			'default' => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$contact_id    = $this->getRequestValue($request, 'user_id', 0);
+		$screen_name   = $this->getRequestValue($request, 'screen_name', '');
+		$profile_url   = $this->getRequestValue($request, 'profile_url', '');
+		$cursor        = $this->getRequestValue($request, 'cursor', -1);
+		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
+		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id      = filter_input(INPUT_GET, 'since_id'     , FILTER_VALIDATE_INT);
-		$max_id        = filter_input(INPUT_GET, 'max_id'       , FILTER_VALIDATE_INT);
-		$min_id        = filter_input(INPUT_GET, 'min_id'       , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
 
diff --git a/src/Module/Api/Twitter/Friends/Lists.php b/src/Module/Api/Twitter/Friends/Lists.php
index dc2c26166d..65dcec8ec6 100644
--- a/src/Module/Api/Twitter/Friends/Lists.php
+++ b/src/Module/Api/Twitter/Friends/Lists.php
@@ -37,21 +37,18 @@ class Lists extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id            = filter_input(INPUT_GET, 'user_id'              , FILTER_VALIDATE_INT);
-		$screen_name           = filter_input(INPUT_GET, 'screen_name');
-		$profile_url           = filter_input(INPUT_GET, 'profile_url');
-		$cursor                = filter_input(INPUT_GET, 'cursor'               , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$skip_status           = filter_input(INPUT_GET, 'skip_status'          , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count                 = filter_input(INPUT_GET, 'count'                , FILTER_VALIDATE_INT, ['options' => [
-			'default' => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$contact_id            = $this->getRequestValue($request, 'user_id', 0);
+		$screen_name           = $this->getRequestValue($request, 'screen_name', '');
+		$profile_url           = $this->getRequestValue($request, 'profile_url', '');
+		$cursor                = $this->getRequestValue($request, 'cursor', -1);
+		$skip_status           = $this->getRequestValue($request, 'skip_status', false);
+		$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
+		$count                 = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id              = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
-		$max_id                = filter_input(INPUT_GET, 'max_id'  , FILTER_VALIDATE_INT);
-		$min_id                = filter_input(INPUT_GET, 'min_id'  , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
 
diff --git a/src/Module/Api/Twitter/Friendships/Incoming.php b/src/Module/Api/Twitter/Friendships/Incoming.php
index 315ef00332..378159c3c2 100644
--- a/src/Module/Api/Twitter/Friendships/Incoming.php
+++ b/src/Module/Api/Twitter/Friendships/Incoming.php
@@ -37,17 +37,14 @@ class Incoming extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$cursor        = filter_input(INPUT_GET, 'cursor'       , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
-		$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
-		$count         = filter_input(INPUT_GET, 'count'        , FILTER_VALIDATE_INT, ['options' => [
-			'default'   => self::DEFAULT_COUNT,
-			'min_range' => 1,
-			'max_range' => self::MAX_COUNT,
-		]]);
+		$cursor        = $this->getRequestValue($request, 'cursor', -1);
+		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
+		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
+
 		// Friendica-specific
-		$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
-		$max_id   = filter_input(INPUT_GET, 'max_id'  , FILTER_VALIDATE_INT);
-		$min_id   = filter_input(INPUT_GET, 'min_id'  , FILTER_VALIDATE_INT);
+		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
 		$params = ['order' => ['cid' => true], 'limit' => $count];
 

From dd8d49d9cf72e7fc7ab2fc70eab3d8d5272358f8 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 17:03:18 +0000
Subject: [PATCH 16/27] Replaced $_REQUEST

---
 src/Module/Api/Mastodon/Media.php             |  2 +-
 .../Api/Twitter/DirectMessagesEndpoint.php    |  2 +-
 src/Module/Api/Twitter/Search/Tweets.php      | 21 +++++++++----------
 3 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php
index d6fcba3e41..1253026fdd 100644
--- a/src/Module/Api/Mastodon/Media.php
+++ b/src/Module/Api/Mastodon/Media.php
@@ -37,7 +37,7 @@ class Media extends BaseApi
 		self::checkAllowedScope(self::SCOPE_WRITE);
 		$uid = self::getCurrentUserID();
 
-		Logger::info('Photo post', ['request' => $_REQUEST, 'files' => $_FILES]);
+		Logger::info('Photo post', ['request' => $request, 'files' => $_FILES]);
 
 		if (empty($_FILES['file'])) {
 			DI::mstdnError()->UnprocessableEntity();
diff --git a/src/Module/Api/Twitter/DirectMessagesEndpoint.php b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
index c0c271dd76..28b867889f 100644
--- a/src/Module/Api/Twitter/DirectMessagesEndpoint.php
+++ b/src/Module/Api/Twitter/DirectMessagesEndpoint.php
@@ -84,7 +84,7 @@ abstract class DirectMessagesEndpoint extends BaseApi
 			$params['order'] = ['id'];
 		}
 
-		$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $_REQUEST['user_id'] ?? 0, 0);
+		$cid = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, 0);
 		if (!empty($cid)) {
 			$cdata = Contact::getPublicAndUserContactID($cid, $uid);
 			if (!empty($cdata['user'])) {
diff --git a/src/Module/Api/Twitter/Search/Tweets.php b/src/Module/Api/Twitter/Search/Tweets.php
index 0d6b5c2308..0aad5a4347 100644
--- a/src/Module/Api/Twitter/Search/Tweets.php
+++ b/src/Module/Api/Twitter/Search/Tweets.php
@@ -41,27 +41,26 @@ class Tweets extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		if (empty($_REQUEST['q'])) {
+		if (empty($request['q'])) {
 			throw new BadRequestException('q parameter is required.');
 		}
 
-		$searchTerm = trim(rawurldecode($_REQUEST['q']));
+		$searchTerm = trim(rawurldecode($request['q']));
 
 		$data['status'] = [];
 
 		$count = 15;
 
-		$exclude_replies = !empty($_REQUEST['exclude_replies']);
-		if (!empty($_REQUEST['rpp'])) {
-			$count = $_REQUEST['rpp'];
-		} elseif (!empty($_REQUEST['count'])) {
-			$count = $_REQUEST['count'];
+		$exclude_replies = !empty($request['exclude_replies']);
+		if (!empty($request['rpp'])) {
+			$count = $request['rpp'];
+		} elseif (!empty($request['count'])) {
+			$count = $request['count'];
 		}
 
-		$since_id = $_REQUEST['since_id'] ?? 0;
-		$max_id   = $_REQUEST['max_id']   ?? 0;
-		$page     = $_REQUEST['page']     ?? 1;
-
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
 		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);

From 6c767743d1bfdfe44c0df37df10b50ba68cce200 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 17:30:23 +0000
Subject: [PATCH 17/27] Improved request value handling

---
 src/Module/Api/Twitter/Search/Tweets.php | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/src/Module/Api/Twitter/Search/Tweets.php b/src/Module/Api/Twitter/Search/Tweets.php
index 0aad5a4347..0e0b2802e2 100644
--- a/src/Module/Api/Twitter/Search/Tweets.php
+++ b/src/Module/Api/Twitter/Search/Tweets.php
@@ -49,19 +49,13 @@ class Tweets extends BaseApi
 
 		$data['status'] = [];
 
-		$count = 15;
-
-		$exclude_replies = !empty($request['exclude_replies']);
-		if (!empty($request['rpp'])) {
-			$count = $request['rpp'];
-		} elseif (!empty($request['count'])) {
-			$count = $request['count'];
-		}
-
+		$count            = $this->getRequestValue($request, 'count', 15);
+		$count            = $this->getRequestValue($request, 'rpp', $count);
 		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
 		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
 		$page             = $this->getRequestValue($request, 'page', 1, 1);
 		$include_entities = $this->getRequestValue($request, 'include_entities', false);
+		$exclude_replies  = $this->getRequestValue($request, 'exclude_replies', false);
 
 		$start = max(0, ($page - 1) * $count);
 

From fd4926b0f387dd9720f3c0415af1f663ce9538fd Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 18:04:05 +0000
Subject: [PATCH 18/27] More parameter handling improved

---
 src/Module/Api/Friendica/Group/Show.php             |  2 +-
 src/Module/Api/Friendica/Photo.php                  |  2 +-
 src/Module/Api/Friendica/Photo/Create.php           |  2 +-
 src/Module/Api/Friendica/Photo/Lists.php            |  2 +-
 src/Module/Api/Friendica/Photo/Update.php           |  2 +-
 src/Module/Api/GNUSocial/Statusnet/Conversation.php |  2 +-
 src/Module/Api/Twitter/DirectMessages/Destroy.php   | 12 ++++++------
 src/Module/Api/Twitter/Favorites.php                | 11 +++++------
 src/Module/Api/Twitter/Statuses/Destroy.php         |  8 +++-----
 src/Module/Api/Twitter/Statuses/Retweet.php         |  8 +++-----
 src/Module/Api/Twitter/Statuses/Show.php            |  8 ++++----
 11 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index ec0bdd1348..1a0e7b6be5 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -36,7 +36,7 @@ class Show extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->parameters['extension'] ?? '';
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');		
 
 		// params
 		$gid = $this->getRequestValue($request, 'gid', 0);
diff --git a/src/Module/Api/Friendica/Photo.php b/src/Module/Api/Friendica/Photo.php
index d0ea25b309..ba87081d45 100644
--- a/src/Module/Api/Friendica/Photo.php
+++ b/src/Module/Api/Friendica/Photo.php
@@ -48,7 +48,7 @@ class Photo extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->parameters['extension'] ?? '';
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
 		if (empty($request['photo_id'])) {
 			throw new HTTPException\BadRequestException('No photo id.');
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
index 0eeb455140..c8ea2fbd78 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -52,7 +52,7 @@ class Create extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->parameters['extension'] ?? '';
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
 		// input params	
 		$desc      = $this->getRequestValue($request, 'desc');
diff --git a/src/Module/Api/Friendica/Photo/Lists.php b/src/Module/Api/Friendica/Photo/Lists.php
index 6d2eb1716c..350d98a1d7 100644
--- a/src/Module/Api/Friendica/Photo/Lists.php
+++ b/src/Module/Api/Friendica/Photo/Lists.php
@@ -54,7 +54,7 @@ class Lists extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->parameters['extension'] ?? '';
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
 		$photos = Photo::selectToArray(['resource-id'], ["`uid` = ? AND NOT `photo-type` IN (?, ?)", $uid, Photo::CONTACT_AVATAR, Photo::CONTACT_BANNER],
 			['order' => ['id'], 'group_by' => ['resource-id']]);
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index ccb9f91503..6723cad538 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -52,7 +52,7 @@ class Update extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->parameters['extension'] ?? '';
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
 		// input params
 		$photo_id  = $this->getRequestValue($request, 'photo_id');
diff --git a/src/Module/Api/GNUSocial/Statusnet/Conversation.php b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
index f21f4c3117..08cfe82fb9 100644
--- a/src/Module/Api/GNUSocial/Statusnet/Conversation.php
+++ b/src/Module/Api/GNUSocial/Statusnet/Conversation.php
@@ -40,7 +40,7 @@ class Conversation extends BaseApi
 		$uid = BaseApi::getCurrentUserID();
 
 		// params
-		$id               = $this->parameters['id'] ?? 0;
+		$id               = $this->getRequestValue($this->parameters, 'id', 0);
 		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
 		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
 		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
diff --git a/src/Module/Api/Twitter/DirectMessages/Destroy.php b/src/Module/Api/Twitter/DirectMessages/Destroy.php
index 3100ff345e..ed0b1ed29e 100644
--- a/src/Module/Api/Twitter/DirectMessages/Destroy.php
+++ b/src/Module/Api/Twitter/DirectMessages/Destroy.php
@@ -52,7 +52,12 @@ class Destroy extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid = BaseApi::getCurrentUserID();
 
-		$id      = $this->getRequestValue($request, 'id', 0);
+		$id = $this->getRequestValue($request, 'id', 0);
+		$id = $this->getRequestValue($this->parameters, 'id', $id);
+		if (empty($id)) {
+			throw new BadRequestException('Message id not specified');
+		}
+
 		$verbose = $this->getRequestValue($request, 'friendica_verbose', false);
 
 		$parenturi = $request['friendica_parenturi'] ?? '';
@@ -64,11 +69,6 @@ class Destroy extends BaseApi
 			return;
 		}
 
-		// BadRequestException if no id specified (for clients using Twitter API)
-		if ($id == 0) {
-			throw new BadRequestException('Message id not specified');
-		}
-
 		// add parent-uri to sql command if specified by calling app
 		$sql_extra = ($parenturi != "" ? " AND `parent-uri` = '" . DBA::escape($parenturi) . "'" : "");
 
diff --git a/src/Module/Api/Twitter/Favorites.php b/src/Module/Api/Twitter/Favorites.php
index e88922af7d..828741a195 100644
--- a/src/Module/Api/Twitter/Favorites.php
+++ b/src/Module/Api/Twitter/Favorites.php
@@ -45,10 +45,11 @@ class Favorites extends BaseApi
 		Logger::info(BaseApi::LOG_PREFIX . 'for {self}', ['module' => 'api', 'action' => 'favorites']);
 
 		// params
-		$count    = $this->getRequestValue($request, 'count', 20, 1, 100);
-		$page     = $this->getRequestValue($request, 'page', 1, 1);
-		$since_id = $this->getRequestValue($request, 'since_id', 0, 0);
-		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
+		$page             = $this->getRequestValue($request, 'page', 1, 1);
+		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
+		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);
+		$include_entities = $this->getRequestValue($request, 'include_entities', false);
 
 		$start = max(0, ($page - 1) * $count);
 
@@ -64,8 +65,6 @@ class Favorites extends BaseApi
 
 		$statuses = Post::selectForUser($uid, [], $condition, $params);
 
-		$include_entities = strtolower(($request['include_entities'] ?? 'false') == 'true');
-
 		$ret = [];
 		while ($status = DBA::fetch($statuses)) {
 			$ret[] = DI::twitterStatus()->createFromUriId($status['uri-id'], $status['uid'], $include_entities)->toArray();
diff --git a/src/Module/Api/Twitter/Statuses/Destroy.php b/src/Module/Api/Twitter/Statuses/Destroy.php
index 7f4a6c6dc7..be08483532 100644
--- a/src/Module/Api/Twitter/Statuses/Destroy.php
+++ b/src/Module/Api/Twitter/Statuses/Destroy.php
@@ -39,11 +39,9 @@ class Destroy extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		if (!empty($this->parameters['id'])) {
-			$id = (int)$this->parameters['id'];
-		} elseif (!empty($request['id'])) {
-			$id = (int)$request['id'];
-		} else {
+		$id = $this->getRequestValue($request, 'id', 0);
+		$id = $this->getRequestValue($this->parameters, 'id', $id);
+		if (empty($id)) {
 			throw new BadRequestException('An id is missing.');
 		}
 
diff --git a/src/Module/Api/Twitter/Statuses/Retweet.php b/src/Module/Api/Twitter/Statuses/Retweet.php
index 0c2401cf31..1d67443b1c 100644
--- a/src/Module/Api/Twitter/Statuses/Retweet.php
+++ b/src/Module/Api/Twitter/Statuses/Retweet.php
@@ -44,11 +44,9 @@ class Retweet extends BaseApi
 		self::checkAllowedScope(self::SCOPE_WRITE);
 		$uid = self::getCurrentUserID();
 
-		if (!empty($this->parameters['id'])) {
-			$id = (int)$this->parameters['id'];
-		} elseif (!empty($request['id'])) {
-			$id = (int)$request['id'];
-		} else {
+		$id = $this->getRequestValue($request, 'id', 0);
+		$id = $this->getRequestValue($this->parameters, 'id', $id);
+		if (empty($id)) {
 			throw new BadRequestException('An id is missing.');
 		}
 
diff --git a/src/Module/Api/Twitter/Statuses/Show.php b/src/Module/Api/Twitter/Statuses/Show.php
index a854837905..64533d0bc9 100644
--- a/src/Module/Api/Twitter/Statuses/Show.php
+++ b/src/Module/Api/Twitter/Statuses/Show.php
@@ -41,10 +41,10 @@ class Show extends BaseApi
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid = BaseApi::getCurrentUserID();
 
-		if (empty($this->parameters['id'])) {
-			$id = intval($request['id'] ?? 0);
-		} else {
-			$id = (int)$this->parameters['id'];
+		$id = $this->getRequestValue($request, 'id', 0);
+		$id = $this->getRequestValue($this->parameters, 'id', $id);
+		if (empty($id)) {
+			throw new BadRequestException('An id is missing.');
 		}
 
 		Logger::notice('API: api_statuses_show: ' . $id);

From 8e8ec9d2d21842c8280e02c310b357be3a5b3fb0 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 18:40:18 +0000
Subject: [PATCH 19/27] Simplified contact id handling

---
 src/Module/Api/Twitter/Followers/Ids.php   | 6 +-----
 src/Module/Api/Twitter/Followers/Lists.php | 6 +-----
 src/Module/Api/Twitter/Friends/Ids.php     | 6 +-----
 src/Module/Api/Twitter/Friends/Lists.php   | 6 +-----
 4 files changed, 4 insertions(+), 20 deletions(-)

diff --git a/src/Module/Api/Twitter/Followers/Ids.php b/src/Module/Api/Twitter/Followers/Ids.php
index d03b547acd..df7120ab62 100644
--- a/src/Module/Api/Twitter/Followers/Ids.php
+++ b/src/Module/Api/Twitter/Followers/Ids.php
@@ -37,9 +37,7 @@ class Ids extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id    = $this->getRequestValue($request, 'user_id', 0);
-		$screen_name   = $this->getRequestValue($request, 'screen_name', '');
-		$profile_url   = $this->getRequestValue($request, 'profile_url', '');
+		$cid           = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
 		$cursor        = $this->getRequestValue($request, 'cursor', -1);
 		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
 		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
@@ -49,8 +47,6 @@ class Ids extends ContactEndpoint
 		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
-		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
-
 		$params = ['order' => ['relation-cid' => true], 'limit' => $count];
 
 		$condition = ['cid' => $cid, 'follows' => true];
diff --git a/src/Module/Api/Twitter/Followers/Lists.php b/src/Module/Api/Twitter/Followers/Lists.php
index 0aca285a19..0e9a2aa82a 100644
--- a/src/Module/Api/Twitter/Followers/Lists.php
+++ b/src/Module/Api/Twitter/Followers/Lists.php
@@ -37,9 +37,7 @@ class Lists extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id            = $this->getRequestValue($request, 'user_id', 0);
-		$screen_name           = $this->getRequestValue($request, 'screen_name', '');
-		$profile_url           = $this->getRequestValue($request, 'profile_url', '');
+		$cid                   = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
 		$cursor                = $this->getRequestValue($request, 'cursor', -1);
 		$skip_status           = $this->getRequestValue($request, 'skip_status', false);
 		$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
@@ -50,8 +48,6 @@ class Lists extends ContactEndpoint
 		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
-		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
-
 		$params = ['order' => ['relation-cid' => true], 'limit' => $count];
 
 		$condition = ['cid' => $cid, 'follows' => true];
diff --git a/src/Module/Api/Twitter/Friends/Ids.php b/src/Module/Api/Twitter/Friends/Ids.php
index c874432e11..b5b571a9f0 100644
--- a/src/Module/Api/Twitter/Friends/Ids.php
+++ b/src/Module/Api/Twitter/Friends/Ids.php
@@ -37,9 +37,7 @@ class Ids extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id    = $this->getRequestValue($request, 'user_id', 0);
-		$screen_name   = $this->getRequestValue($request, 'screen_name', '');
-		$profile_url   = $this->getRequestValue($request, 'profile_url', '');
+		$cid           = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
 		$cursor        = $this->getRequestValue($request, 'cursor', -1);
 		$stringify_ids = $this->getRequestValue($request, 'stringify_ids', false);
 		$count         = $this->getRequestValue($request, 'count', self::DEFAULT_COUNT, 1, self::MAX_COUNT);
@@ -49,8 +47,6 @@ class Ids extends ContactEndpoint
 		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
-		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
-
 		$params = ['order' => ['cid' => true], 'limit' => $count];
 
 		$condition = ['relation-cid' => $cid, 'follows' => true];
diff --git a/src/Module/Api/Twitter/Friends/Lists.php b/src/Module/Api/Twitter/Friends/Lists.php
index 65dcec8ec6..750ba6db61 100644
--- a/src/Module/Api/Twitter/Friends/Lists.php
+++ b/src/Module/Api/Twitter/Friends/Lists.php
@@ -37,9 +37,7 @@ class Lists extends ContactEndpoint
 		$uid = BaseApi::getCurrentUserID();
 
 		// Expected value for user_id parameter: public/user contact id
-		$contact_id            = $this->getRequestValue($request, 'user_id', 0);
-		$screen_name           = $this->getRequestValue($request, 'screen_name', '');
-		$profile_url           = $this->getRequestValue($request, 'profile_url', '');
+		$cid                   = BaseApi::getContactIDForSearchterm($request['screen_name'] ?? '', $request['profileurl'] ?? '', $request['user_id'] ?? 0, $uid);
 		$cursor                = $this->getRequestValue($request, 'cursor', -1);
 		$skip_status           = $this->getRequestValue($request, 'skip_status', false);
 		$include_user_entities = $this->getRequestValue($request, 'include_user_entities', false);
@@ -50,8 +48,6 @@ class Lists extends ContactEndpoint
 		$max_id   = $this->getRequestValue($request, 'max_id', 0, 0);
 		$min_id   = $this->getRequestValue($request, 'min_id', 0, 0);
 
-		$cid = BaseApi::getContactIDForSearchterm($screen_name, $profile_url, $contact_id, $uid);
-
 		$params = ['order' => ['cid' => true], 'limit' => $count];
 
 		$condition = ['relation-cid' => $cid, 'follows' => true];

From 0e157150882bda71e3ba9c2ba56162db8cd897e3 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 19:38:59 +0000
Subject: [PATCH 20/27] Simplifying extension access

---
 src/Module/Api/Friendica/Activity.php              | 2 +-
 src/Module/Api/Friendica/Notification.php          | 2 +-
 src/Module/Api/Friendica/Profile/Show.php          | 2 +-
 src/Module/Api/GNUSocial/Help/Test.php             | 2 +-
 src/Module/Api/Twitter/Account/RateLimitStatus.php | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/Module/Api/Friendica/Activity.php b/src/Module/Api/Friendica/Activity.php
index 70aeee613f..3915c2089e 100644
--- a/src/Module/Api/Friendica/Activity.php
+++ b/src/Module/Api/Friendica/Activity.php
@@ -52,7 +52,7 @@ class Activity extends BaseApi
 		$res = Item::performActivity($request['id'], $this->parameters['verb'], $uid);
 
 		if ($res) {
-			if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
+			if ($this->parameters['extension'] ?? '' == 'xml') {
 				$ok = 'true';
 			} else {
 				$ok = 'ok';
diff --git a/src/Module/Api/Friendica/Notification.php b/src/Module/Api/Friendica/Notification.php
index 1f5ac9b488..d16e0e2b0d 100644
--- a/src/Module/Api/Friendica/Notification.php
+++ b/src/Module/Api/Friendica/Notification.php
@@ -43,7 +43,7 @@ class Notification extends BaseApi
 			$notifications[] = new ApiNotification($Notify);
 		}
 
-		if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
+		if ($this->parameters['extension'] ?? '' == 'xml') {
 			$xmlnotes = [];
 			foreach ($notifications as $notification) {
 				$xmlnotes[] = ['@attributes' => $notification->toArray()];
diff --git a/src/Module/Api/Friendica/Profile/Show.php b/src/Module/Api/Friendica/Profile/Show.php
index 60f4f024b0..2507b7e275 100644
--- a/src/Module/Api/Friendica/Profile/Show.php
+++ b/src/Module/Api/Friendica/Profile/Show.php
@@ -48,7 +48,7 @@ class Show extends BaseApi
 		$profile = self::formatProfile($profile, $profileFields);
 
 		$profiles = [];
-		if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
+		if ($this->parameters['extension'] ?? '' == 'xml') {
 			$profiles['0:profile'] = $profile;
 		} else {
 			$profiles[] = $profile;
diff --git a/src/Module/Api/GNUSocial/Help/Test.php b/src/Module/Api/GNUSocial/Help/Test.php
index 4cfeda6aba..44a31ba880 100644
--- a/src/Module/Api/GNUSocial/Help/Test.php
+++ b/src/Module/Api/GNUSocial/Help/Test.php
@@ -31,7 +31,7 @@ class Test extends BaseApi
 {
 	protected function rawContent(array $request = [])
 	{
-		if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
+		if ($this->parameters['extension'] ?? '' == 'xml') {
 			$ok = 'true';
 		} else {
 			$ok = 'ok';
diff --git a/src/Module/Api/Twitter/Account/RateLimitStatus.php b/src/Module/Api/Twitter/Account/RateLimitStatus.php
index 7a48f4f0e0..60cee6ce34 100644
--- a/src/Module/Api/Twitter/Account/RateLimitStatus.php
+++ b/src/Module/Api/Twitter/Account/RateLimitStatus.php
@@ -31,7 +31,7 @@ class RateLimitStatus extends BaseApi
 {
 	protected function rawContent(array $request = [])
 	{
-		if (!empty($this->parameters['extension']) && ($this->parameters['extension'] == 'xml')) {
+		if ($this->parameters['extension'] ?? '' == 'xml') {
 			$hash = [
 				'remaining-hits'        => '150',
 				'@attributes'           => ["type" => "integer"],

From dc48f9b8f079d6270b00b8b7eab26109c4c4b0b2 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:17:31 +0000
Subject: [PATCH 21/27] White spaces

---
 src/Factory/Api/Friendica/Photo.php              |  7 ++++---
 src/Module/Api/Friendica/Group/Show.php          |  2 +-
 src/Module/Api/Friendica/Photo/Create.php        |  2 +-
 src/Module/Api/Friendica/Photo/Update.php        |  8 ++++----
 .../Api/Twitter/Account/UpdateProfileImage.php   | 16 ++++++++--------
 src/Module/Api/Twitter/Search/Tweets.php         |  2 +-
 6 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/src/Factory/Api/Friendica/Photo.php b/src/Factory/Api/Friendica/Photo.php
index 9c0a48dea7..dad90d13f1 100644
--- a/src/Factory/Api/Friendica/Photo.php
+++ b/src/Factory/Api/Friendica/Photo.php
@@ -91,9 +91,9 @@ class Photo extends BaseFactory
 			$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'],
+					'type'  => $data['type'],
 					'scale' => $photo['scale'],
-					'href' => $link
+					'href'  => $link
 				];
 			} else {
 				$data['link'][$id] = $link;
@@ -108,6 +108,7 @@ class Photo extends BaseFactory
 		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)) {
@@ -147,7 +148,7 @@ class Photo extends BaseFactory
 		} elseif ($with_posts) {
 			$data['friendica_activities'] = [];
 			$data['friendica_comments']   = [];
-			$data['rights_mismatch'] = false;
+			$data['rights_mismatch']      = false;
 		}
 
 		return $data;
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index 1a0e7b6be5..d150827694 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -36,7 +36,7 @@ class Show extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
 		$uid  = BaseApi::getCurrentUserID();
-		$type = $this->getRequestValue($this->parameters, 'extension', 'json');		
+		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
 		// params
 		$gid = $this->getRequestValue($request, 'gid', 0);
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
index c8ea2fbd78..b0dc5d7a14 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -54,7 +54,7 @@ class Create extends BaseApi
 		$uid  = BaseApi::getCurrentUserID();
 		$type = $this->getRequestValue($this->parameters, 'extension', 'json');
 
-		// input params	
+		// input params
 		$desc      = $this->getRequestValue($request, 'desc');
 		$album     = $this->getRequestValue($request, 'album');
 		$allow_cid = $this->getRequestValue($request, 'allow_cid');
diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php
index 6723cad538..44fd554b09 100644
--- a/src/Module/Api/Friendica/Photo/Update.php
+++ b/src/Module/Api/Friendica/Photo/Update.php
@@ -96,22 +96,22 @@ class Update extends BaseApi
 		}
 
 		if (!is_null($allow_cid)) {
-			$allow_cid = trim($allow_cid);
+			$allow_cid                   = trim($allow_cid);
 			$updated_fields['allow_cid'] = $allow_cid;
 		}
 
 		if (!is_null($deny_cid)) {
-			$deny_cid = trim($deny_cid);
+			$deny_cid                   = trim($deny_cid);
 			$updated_fields['deny_cid'] = $deny_cid;
 		}
 
 		if (!is_null($allow_gid)) {
-			$allow_gid = trim($allow_gid);
+			$allow_gid                   = trim($allow_gid);
 			$updated_fields['allow_gid'] = $allow_gid;
 		}
 
 		if (!is_null($deny_gid)) {
-			$deny_gid = trim($deny_gid);
+			$deny_gid                   = trim($deny_gid);
 			$updated_fields['deny_gid'] = $deny_gid;
 		}
 
diff --git a/src/Module/Api/Twitter/Account/UpdateProfileImage.php b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
index 02194316b2..5af835289a 100644
--- a/src/Module/Api/Twitter/Account/UpdateProfileImage.php
+++ b/src/Module/Api/Twitter/Account/UpdateProfileImage.php
@@ -37,36 +37,36 @@ class UpdateProfileImage extends BaseApi
 	{
 		BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
 		$uid = BaseApi::getCurrentUserID();
-	
+
 		// get mediadata from image or media (Twitter call api/account/update_profile_image provides image)
 		if (!empty($_FILES['image'])) {
 			$media = $_FILES['image'];
 		} elseif (!empty($_FILES['media'])) {
 			$media = $_FILES['media'];
 		}
-	
+
 		// error if image data is missing
 		if (empty($media)) {
 			throw new HTTPException\BadRequestException('no media data submitted');
 		}
-		
+
 		// save new profile image
 		$resource_id = Photo::uploadAvatar($uid, $media);
 		if (empty($resource_id)) {
 			throw new HTTPException\InternalServerErrorException('image upload failed');
 		}
-	
+
 		// output for client
 		$skip_status = $this->getRequestValue($request, 'skip_status', false);
-	
+
 		$user_info = DI::twitterUser()->createFromUserId($uid, $skip_status)->toArray();
-	
+
 		// "verified" isn't used here in the standard
 		unset($user_info['verified']);
-	
+
 		// "uid" is only needed for some internal stuff, so remove it from here
 		unset($user_info['uid']);
-	
+
 		$this->response->exit('user', ['user' => $user_info], $this->parameters['extension'] ?? null);
 	}
 }
diff --git a/src/Module/Api/Twitter/Search/Tweets.php b/src/Module/Api/Twitter/Search/Tweets.php
index 0e0b2802e2..5da579b7ce 100644
--- a/src/Module/Api/Twitter/Search/Tweets.php
+++ b/src/Module/Api/Twitter/Search/Tweets.php
@@ -49,7 +49,7 @@ class Tweets extends BaseApi
 
 		$data['status'] = [];
 
-		$count            = $this->getRequestValue($request, 'count', 15);
+		$count            = $this->getRequestValue($request, 'count', 20, 1, 100);
 		$count            = $this->getRequestValue($request, 'rpp', $count);
 		$since_id         = $this->getRequestValue($request, 'since_id', 0, 0);
 		$max_id           = $this->getRequestValue($request, 'max_id', 0, 0);

From 88ac888a3b3e8a5632d8af00ee76644b5fe9b147 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:25:46 +0000
Subject: [PATCH 22/27] Fix some tests

---
 tests/src/Factory/Api/Twitter/ActivitiesTest.php    | 4 ++--
 tests/src/Factory/Api/Twitter/StatusTest.php        | 2 +-
 tests/src/Module/Api/Twitter/Lists/StatusesTest.php | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/src/Factory/Api/Twitter/ActivitiesTest.php b/tests/src/Factory/Api/Twitter/ActivitiesTest.php
index 349537468e..7acdc09556 100644
--- a/tests/src/Factory/Api/Twitter/ActivitiesTest.php
+++ b/tests/src/Factory/Api/Twitter/ActivitiesTest.php
@@ -36,7 +36,7 @@ class ActivitiesTest extends FixtureTest
 	{
 		$item = ['uid' => 0, 'uri-id' => 1];
 
-		$result = (new Activities(DI::logger(), DI::baseUrl(), DI::twitterUser()))
+		$result = (new Activities(DI::logger(), DI::twitterUser()))
 			->createFromUriId($item['uri-id'], $item['uid']);
 
 		self::assertArrayHasKey('like', $result);
@@ -55,7 +55,7 @@ class ActivitiesTest extends FixtureTest
 	{
 		$item = ['uid' => 0, 'uri-id' => 1];
 
-		$result = (new Activities(DI::logger(), DI::baseUrl(), DI::twitterUser()))
+		$result = (new Activities(DI::logger(), DI::twitterUser()))
 			->createFromUriId($item['uri-id'], $item['uid'], 'xml');
 
 		self::assertArrayHasKey('friendica:like', $result);
diff --git a/tests/src/Factory/Api/Twitter/StatusTest.php b/tests/src/Factory/Api/Twitter/StatusTest.php
index 337fab086f..f608b66bb1 100644
--- a/tests/src/Factory/Api/Twitter/StatusTest.php
+++ b/tests/src/Factory/Api/Twitter/StatusTest.php
@@ -48,7 +48,7 @@ class StatusTest extends FixtureTest
 			new Media(DI::logger(), DI::baseUrl()),
 			new Url(DI::logger()),
 			new Mention(DI::logger(), DI::baseUrl()),
-			new Activities(DI::logger(), DI::baseUrl(), DI::twitterUser()),
+			new Activities(DI::logger(), DI::twitterUser()),
 			new Attachment(DI::logger()));
 	}
 
diff --git a/tests/src/Module/Api/Twitter/Lists/StatusesTest.php b/tests/src/Module/Api/Twitter/Lists/StatusesTest.php
index 1f9226b84a..8bc8257c0c 100644
--- a/tests/src/Module/Api/Twitter/Lists/StatusesTest.php
+++ b/tests/src/Module/Api/Twitter/Lists/StatusesTest.php
@@ -38,7 +38,7 @@ class StatusesTest extends ApiTest
 	{
 		$this->expectException(BadRequestException::class);
 
-		(new Statuses(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))
+		(new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))
 			->run();
 	}
 
@@ -47,7 +47,7 @@ class StatusesTest extends ApiTest
 	 */
 	public function testApiListsStatusesWithListId()
 	{
-		$response = (new Statuses(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))
+		$response = (new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))
 			->run([
 				'list_id' => 1,
 				'page'    => -1,
@@ -67,7 +67,7 @@ class StatusesTest extends ApiTest
 	 */
 	public function testApiListsStatusesWithListIdAndRss()
 	{
-		$response = (new Statuses(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'rss']))
+		$response = (new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'rss']))
 			->run([
 				'list_id' => 1
 			]);

From 0f7b48c53e461461ab694d2b34ca537d6f590db8 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:37:50 +0000
Subject: [PATCH 23/27] Fix wrong return value

---
 tests/src/Module/Api/GnuSocial/Help/TestTest.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/src/Module/Api/GnuSocial/Help/TestTest.php b/tests/src/Module/Api/GnuSocial/Help/TestTest.php
index be0e187a63..28e7ab5ea3 100644
--- a/tests/src/Module/Api/GnuSocial/Help/TestTest.php
+++ b/tests/src/Module/Api/GnuSocial/Help/TestTest.php
@@ -51,6 +51,6 @@ class TestTest extends ApiTest
 			'Content-type'                => ['text/xml'],
 			ICanCreateResponses::X_HEADER => ['xml']
 		], $response->getHeaders());
-		self::assertxml($response->getBody(), 'ok');
+		self::assertxml($response->getBody(), 'true');
 	}
 }

From b38c9bed6f06430dcab8c0de78694e178e04fd18 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 16 Jan 2022 21:47:12 +0100
Subject: [PATCH 24/27] Apply suggestions from code review

Co-authored-by: Philipp <admin+Github@philipp.info>
---
 src/Factory/Api/Friendica/Group.php       | 9 ++++++---
 src/Module/Api/Friendica/Group/Show.php   | 1 -
 src/Module/Api/Friendica/Photo/Create.php | 1 -
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/Factory/Api/Friendica/Group.php b/src/Factory/Api/Friendica/Group.php
index 945971c285..b740e4fe92 100644
--- a/src/Factory/Api/Friendica/Group.php
+++ b/src/Factory/Api/Friendica/Group.php
@@ -22,7 +22,7 @@
 namespace Friendica\Factory\Api\Friendica;
 
 use Friendica\BaseFactory;
-use Friendica\Database\DBA;
+use Friendica\Database\Database;
 use Friendica\Network\HTTPException;
 use Psr\Log\LoggerInterface;
 use Friendica\Factory\Api\Twitter\User as TwitterUser;
@@ -31,12 +31,15 @@ class Group extends BaseFactory
 {
 	/** @var twitterUser entity */
 	private $twitterUser;
+	/** @var Database */
+	private $database;
 
-	public function __construct(LoggerInterface $logger, TwitterUser $twitteruser)
+	public function __construct(LoggerInterface $logger, TwitterUser $twitteruser, Database $dba)
 	{
 		parent::__construct($logger);
 
 		$this->twitterUser = $twitteruser;
+		$this->dba = $dba;
 	}
 
 	/**
@@ -46,7 +49,7 @@ class Group extends BaseFactory
 	 */
 	public function createFromId(int $id): array
 	{
-		$group = DBA::selectFirst('group', [], ['id' => $id, 'deleted' => false]);
+		$group = $this->dba->selectFirst('group', [], ['id' => $id, 'deleted' => false]);
 		if (empty($group)) {
 			return [];
 		}
diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index d150827694..8a479930d5 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -22,7 +22,6 @@
 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;
diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php
index b0dc5d7a14..c207820b0f 100644
--- a/src/Module/Api/Friendica/Photo/Create.php
+++ b/src/Module/Api/Friendica/Photo/Create.php
@@ -90,7 +90,6 @@ class Create extends BaseApi
 		if (!empty($photo)) {
 			$data = ['photo' => $this->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');
 		}

From 71cf72cc8bde161471b2294c675fb0500dd48399 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:49:59 +0000
Subject: [PATCH 25/27] Standards

---
 src/Factory/Api/Friendica/Group.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Factory/Api/Friendica/Group.php b/src/Factory/Api/Friendica/Group.php
index b740e4fe92..868231c98b 100644
--- a/src/Factory/Api/Friendica/Group.php
+++ b/src/Factory/Api/Friendica/Group.php
@@ -32,14 +32,14 @@ class Group extends BaseFactory
 	/** @var twitterUser entity */
 	private $twitterUser;
 	/** @var Database */
-	private $database;
+	private $dba;
 
 	public function __construct(LoggerInterface $logger, TwitterUser $twitteruser, Database $dba)
 	{
 		parent::__construct($logger);
 
 		$this->twitterUser = $twitteruser;
-		$this->dba = $dba;
+		$this->dba         = $dba;
 	}
 
 	/**

From 55679a6021cfd0cda286571ad0110f145705ab92 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:54:14 +0000
Subject: [PATCH 26/27] Possibly fixing one test

---
 src/Module/Api/Friendica/Group/Show.php           | 1 +
 src/Module/Api/Twitter/DirectMessages/Destroy.php | 3 ---
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Group/Show.php
index 8a479930d5..d150827694 100644
--- a/src/Module/Api/Friendica/Group/Show.php
+++ b/src/Module/Api/Friendica/Group/Show.php
@@ -22,6 +22,7 @@
 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;
diff --git a/src/Module/Api/Twitter/DirectMessages/Destroy.php b/src/Module/Api/Twitter/DirectMessages/Destroy.php
index ed0b1ed29e..9de0982364 100644
--- a/src/Module/Api/Twitter/DirectMessages/Destroy.php
+++ b/src/Module/Api/Twitter/DirectMessages/Destroy.php
@@ -54,9 +54,6 @@ class Destroy extends BaseApi
 
 		$id = $this->getRequestValue($request, 'id', 0);
 		$id = $this->getRequestValue($this->parameters, 'id', $id);
-		if (empty($id)) {
-			throw new BadRequestException('Message id not specified');
-		}
 
 		$verbose = $this->getRequestValue($request, 'friendica_verbose', false);
 

From 51dcfe134ecf536389827a563bd95f8354b50132 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 16 Jan 2022 20:58:58 +0000
Subject: [PATCH 27/27] fixing some more tests

---
 src/Module/Api/Friendica/Activity.php              | 2 +-
 src/Module/Api/Friendica/Notification.php          | 2 +-
 src/Module/Api/Friendica/Profile/Show.php          | 2 +-
 src/Module/Api/GNUSocial/Help/Test.php             | 2 +-
 src/Module/Api/Twitter/Account/RateLimitStatus.php | 2 +-
 tests/src/Module/Api/GnuSocial/Help/TestTest.php   | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/Module/Api/Friendica/Activity.php b/src/Module/Api/Friendica/Activity.php
index 3915c2089e..3c892b3030 100644
--- a/src/Module/Api/Friendica/Activity.php
+++ b/src/Module/Api/Friendica/Activity.php
@@ -52,7 +52,7 @@ class Activity extends BaseApi
 		$res = Item::performActivity($request['id'], $this->parameters['verb'], $uid);
 
 		if ($res) {
-			if ($this->parameters['extension'] ?? '' == 'xml') {
+			if (($this->parameters['extension'] ?? '') == 'xml') {
 				$ok = 'true';
 			} else {
 				$ok = 'ok';
diff --git a/src/Module/Api/Friendica/Notification.php b/src/Module/Api/Friendica/Notification.php
index d16e0e2b0d..46320df153 100644
--- a/src/Module/Api/Friendica/Notification.php
+++ b/src/Module/Api/Friendica/Notification.php
@@ -43,7 +43,7 @@ class Notification extends BaseApi
 			$notifications[] = new ApiNotification($Notify);
 		}
 
-		if ($this->parameters['extension'] ?? '' == 'xml') {
+		if (($this->parameters['extension'] ?? '') == 'xml') {
 			$xmlnotes = [];
 			foreach ($notifications as $notification) {
 				$xmlnotes[] = ['@attributes' => $notification->toArray()];
diff --git a/src/Module/Api/Friendica/Profile/Show.php b/src/Module/Api/Friendica/Profile/Show.php
index 2507b7e275..2d686d9cae 100644
--- a/src/Module/Api/Friendica/Profile/Show.php
+++ b/src/Module/Api/Friendica/Profile/Show.php
@@ -48,7 +48,7 @@ class Show extends BaseApi
 		$profile = self::formatProfile($profile, $profileFields);
 
 		$profiles = [];
-		if ($this->parameters['extension'] ?? '' == 'xml') {
+		if (($this->parameters['extension'] ?? '') == 'xml') {
 			$profiles['0:profile'] = $profile;
 		} else {
 			$profiles[] = $profile;
diff --git a/src/Module/Api/GNUSocial/Help/Test.php b/src/Module/Api/GNUSocial/Help/Test.php
index 44a31ba880..ecf99c78bf 100644
--- a/src/Module/Api/GNUSocial/Help/Test.php
+++ b/src/Module/Api/GNUSocial/Help/Test.php
@@ -31,7 +31,7 @@ class Test extends BaseApi
 {
 	protected function rawContent(array $request = [])
 	{
-		if ($this->parameters['extension'] ?? '' == 'xml') {
+		if (($this->parameters['extension'] ?? '') == 'xml') {
 			$ok = 'true';
 		} else {
 			$ok = 'ok';
diff --git a/src/Module/Api/Twitter/Account/RateLimitStatus.php b/src/Module/Api/Twitter/Account/RateLimitStatus.php
index 60cee6ce34..c5f052b394 100644
--- a/src/Module/Api/Twitter/Account/RateLimitStatus.php
+++ b/src/Module/Api/Twitter/Account/RateLimitStatus.php
@@ -31,7 +31,7 @@ class RateLimitStatus extends BaseApi
 {
 	protected function rawContent(array $request = [])
 	{
-		if ($this->parameters['extension'] ?? '' == 'xml') {
+		if (($this->parameters['extension'] ?? '') == 'xml') {
 			$hash = [
 				'remaining-hits'        => '150',
 				'@attributes'           => ["type" => "integer"],
diff --git a/tests/src/Module/Api/GnuSocial/Help/TestTest.php b/tests/src/Module/Api/GnuSocial/Help/TestTest.php
index 28e7ab5ea3..be0e187a63 100644
--- a/tests/src/Module/Api/GnuSocial/Help/TestTest.php
+++ b/tests/src/Module/Api/GnuSocial/Help/TestTest.php
@@ -51,6 +51,6 @@ class TestTest extends ApiTest
 			'Content-type'                => ['text/xml'],
 			ICanCreateResponses::X_HEADER => ['xml']
 		], $response->getHeaders());
-		self::assertxml($response->getBody(), 'true');
+		self::assertxml($response->getBody(), 'ok');
 	}
 }