+++ /dev/null
-<?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);
switch ($simplehtml) {
case self::API:
$text = ($is_quote_share? '<br>' : '') .
- '<b><a href="' . $attributes['link'] . '">' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b><br>\n" .
+ '<b><a href="' . $attributes['link'] . '">' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b><br>\n" .
'<blockquote class="shared_content">' . $content . '</blockquote>';
break;
case self::DIASPORA:
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
*/
--- /dev/null
+<?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();
+ }
+}
--- /dev/null
+<?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
--- /dev/null
+<?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);
+ }
+}
--- /dev/null
+<?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);
+ }
+}
+++ /dev/null
-<?php
-/**
- * @copyright Copyright (C) 2010-2022, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Module\Api\Friendica;
-
-use Friendica\DI;
-use Friendica\Module\BaseApi;
-require_once __DIR__ . '/../../../../include/api.php';
-
-/**
- * api/friendica
- *
- * @package Friendica\Module\Api\Friendica
- */
-class Index extends BaseApi
-{
- protected function post(array $request = [])
- {
- self::checkAllowedScope(self::SCOPE_WRITE);
- }
-
- protected function delete(array $request = [])
- {
- self::checkAllowedScope(self::SCOPE_WRITE);
- }
-
- protected function rawContent(array $request = [])
- {
- echo api_call(DI::args()->getCommand(), $this->parameters['extension'] ?? 'json');
- exit();
- }
-}
--- /dev/null
+<?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));
+ }
+}
--- /dev/null
+<?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');
+ }
+ }
+}
--- /dev/null
+<?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));
+ }
+}
--- /dev/null
+<?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');
+ }
+}
--- /dev/null
+<?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);
+ }
+}
--- /dev/null
+<?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));
+ }
+}
--- /dev/null
+<?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));
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Module\Api\Twitter\Lists;
+
+use Friendica\Module\BaseApi;
+use Friendica\Model\Contact;
+
+/**
+ * Returns all lists the user subscribes to.
+ *
+ * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
+ */
+class Lists extends BaseApi
+{
+ protected function rawContent(array $request = [])
+ {
+ BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
+ $uid = BaseApi::getCurrentUserID();
+
+ // This is a dummy endpoint
+ $ret = [];
+ $this->response->exit('statuses', ["lists_list" => $ret], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
+ }
+}
--- /dev/null
+<?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));
+ }
+}
--- /dev/null
+<?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));
+ }
+ }
+}
--- /dev/null
+<?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';
+ }
+}
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
*
$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;
}
$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 ]],
'/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 ]],
'/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]],
namespace Friendica\Test\legacy;
use Friendica\App;
-use Friendica\Core\ACL;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\DI;
use Friendica\Module\BaseApi;
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.
*
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.
*
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.
*
)
);
}
-
- /**
- * 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();
- }
}