Merge pull request #7904 from MrPetovan/task/7887-api-followers-request

Add GET /api/v1/follow_requests Mastodon API endpoint
This commit is contained in:
Philipp 2019-12-10 15:53:06 +01:00 committed by GitHub
commit d0b20fb499
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 3765 additions and 2214 deletions

1458
doc/API-Entities.md Normal file

File diff suppressed because it is too large Load diff

682
doc/API-Friendica.md Normal file
View file

@ -0,0 +1,682 @@
# Friendica API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following specific endpoints.
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints uses the [Friendica API entities](help/API-Entities).
## Endpoints
### GET api/externalprofile/show
Returns a [Contact](help/API-Entities#Contact) entity for the provided profile URL.
#### Parameters
- `profileurl`: Profile URL
### GET api/statuses/public_timeline
Returns a list of public [Items](help/API-Entities#Item) posted on this node.
Equivalent of the local community page.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `exclude_replies`: don't show replies (default: false)
* `conversation_id`: Shows all statuses of a given conversation.
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `trim_user`
### GET api/statuses/networkpublic_timeline
Returns a list of public [Items](help/API-Entities#Item) this node is aware of.
Equivalent of the global community page.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `exclude_replies`: don't show replies (default: false)
* `conversation_id`: Shows all statuses of a given conversation.
* `include_entities`: "true" shows entities for pictures and links (Default: false)
### GET api/statuses/replies
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `include_rts`
* `trim_user`
* `contributor_details`
---
### GET api/conversation/show
Unofficial Twitter command. It shows all direct answers (excluding the original post) to a given id.
#### Parameters
* `id`: id of the post
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `include_rts`
* `trim_user`
* `contributor_details`
### GET api/statusnet/conversation
Alias of [`api/conversation/show`](#GET+api%2Fconversation%2Fshow).
### GET api/statusnet/config
Returns the public Friendica node configuration.
### GET api/gnusocial/config
Alias of [`api/statusnet/config`](#GET+api%2Fstatusnet%2Fconfig).
### GET api/statusnet/version
Returns a fake static StatusNet protocol version.
### GET api/gnusocial/version
Alias of [`api/statusnet/version`](#GET+api%2Fstatusnet%2Fversion).
---
### POST api/friendica/activity/[verb]
Add or remove an activity from an item.
'verb' can be one of:
* `like`
* `dislike`
* `attendyes`
* `attendno`
* `attendmaybe`
To remove an activity, prepend the verb with "un", eg. "unlike" or "undislike"
Attend verbs disable eachother: that means that if "attendyes" was added to an item, adding "attendno" remove previous "attendyes".
Attend verbs should be used only with event-related items (there is no check at the moment).
#### Parameters
* `id`: item id
#### Return values
On success:
json:
```"ok"```
xml:
```<ok>true</ok>```
On error:
HTTP 400 BadRequest
---
### GET api/direct_messages
Deprecated Twitter received direct message list endpoint.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `include_entities`: "true" shows entities for pictures and links (Default: false)
* `friendica_verbose`: "true" enables different error returns (default: "false")
#### Unsupported parameters
* `skip_status`
### GET api/direct_messages/all
Returns all [Private Messages](help/API-Entities#Private+message).
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `friendica_verbose`: "true" enables different error returns (default: "false")
### GET api/direct_messages/conversation
Returns all replies of a single private message conversation. Returns [Private Messages](help/API-Entities#Private+message)
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `uri`: URI of the conversation
* `friendica_verbose`: "true" enables different error returns (default: "false")
### GET api/direct_messages/sent
Deprecated Twitter sent direct message list endpoint. Returns [Private Messages](help/API-Entities#Private+message).
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `include_entities`: "true" shows entities for pictures and links (Default: false)
* `friendica_verbose`: "true" enables different error returns (default: "false")
### POST/PUT api/direct_messages/new
Deprecated Twitter direct message submission endpoint.
#### Parameters
* `user_id`: id of the user
* `screen_name`: screen name (for technical reasons, this value is not unique!)
* `text`: The message
* `replyto`: ID of the replied direct message
* `title`: Title of the direct message
### POST/DELETE api/direct_messages/destroy
Deprecated Twitter direct message deletion endpoint.
#### Parameters
* `id`: id of the message to be deleted
* `include_entities`: optional, currently not yet implemented
* `friendica_parenturi`: optional, can be used for increased safety to delete only intended messages
* `friendica_verbose`: "true" enables different error returns (default: "false")
#### Return values
On success:
* JSON return as defined for Twitter API not yet implemented
* on friendica_verbose=true: JSON return {"result":"ok","message":"message deleted"}
On error:
HTTP 400 BadRequest
* on friendica_verbose=true: different JSON returns {"result":"error","message":"xyz"}
### GET api/friendica/direct_messages_setseen
#### Parameters
* `id`: id of the message to be updated as seen
#### Return values
On success:
* JSON return `{"result": "ok", "message": "message set to seen"}`
On error:
* different JSON returns `{"result": "error", "message": "xyz"}`
### GET api/friendica/direct_messages_search (GET; AUTH)
Returns [Private Messages](help/API-Entities#Private+message) matching the provided search string.
#### Parameters
* `searchstring`: string for which the API call should search as '%searchstring%' in field 'body' of all messages of the authenticated user (caption ignored)
* `getText` (optional): `plain`|`html` If ommited, the title is prepended to the plaintext body in the `text` attribute of the private message objects.
* `getUserObjects` (optional): `true`|`false` If `false`, the `sender` and `recipient` attributes of the private message object are absent.
#### Return values
Returns only tested with JSON, XML might work as well.
On success:
* JSON return `{"success":"true", "search_results": array of found messages}`
* JSOn return `{"success":"false", "search_results": "nothing found"}`
On error:
* different JSON returns `{"result": "error", "message": "searchstring not specified"}`
---
### GET api/friendica/group_show
Return all or a specified group of the user with the containing contacts as array.
#### Parameters
* `gid`: optional, if not given, API returns all groups of the user
#### Return values
Array of:
* `name`: name of the group
* `gid`: id of the group
* `user`: array of [Contacts](help/API-Entities#Contact)
### POST/PUT api/friendica/group_create
Create the group with the posted array of contacts as members.
#### Parameters
* `name`: name of the group to be created
#### POST data
JSON data as Array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show):
* `gid`
* `name`
* List of [Contacts](help/API-Entities#Contact)
#### Return values
Array of:
* `success`: true if successfully created or reactivated
* `gid`: gid of the created group
* `name`: name of the created group
* `status`: "missing user" | "reactivated" | "ok"
* `wrong users`: array of users, which were not available in the contact table
### POST api/friendica/group_update
Update the group with the posted array of contacts as members (post all members of the group to the call; function will remove members not posted).
#### Parameters
* `gid`: id of the group to be changed
* `name`: name of the group to be changed
#### POST data
JSON data as array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show):
* `gid`
* `name`
* List of [Contacts](help/API-Entities#Contact)
#### Return values
Array of:
* `success`: true if successfully updated
* `gid`: gid of the changed group
* `name`: name of the changed group
* `status`: "missing user" | "ok"
* `wrong users`: array of users, which were not available in the contact table
### POST/DELETE api/friendica/group_delete
Delete the specified group of contacts; API call need to include the correct gid AND name of the group to be deleted.
#### Parameters
* `gid`: id of the group to be deleted
* `name`: name of the group to be deleted
#### Return values
Array of:
* `success`: true if successfully deleted
* `gid`: gid of the deleted group
* `name`: name of the deleted group
* `status`: "deleted" if successfully deleted
* `wrong users`: empty array
---
### GET api/friendica/notifications
Return last 50 [Notifications](help/API-Entities#Notification) for the current user, ordered by date with unseen item on top.
#### Parameters
none
### POST api/friendica/notifications/seen
Set notification as seen.
#### Parameters
- `id`: id of the notification to set seen
#### Return values
If the note is linked to an item, returns an [Item](help/API-Entities#Item).
Otherwise, a success status is returned:
* `success` (json) | `<status>success</status>` (xml)
---
### GET api/friendica/photo
Returns a [Photo](help/API-Entities#Photo).
#### Parameters
* `photo_id`: Resource id of a photo.
* `scale`: (optional) scale value of the photo
Returns data of a picture with the given resource.
If 'scale' isn't provided, returned data include full url to each scale of the photo.
If 'scale' is set, returned data include image data base64 encoded.
possibile scale value are:
* 0: original or max size by server settings
* 1: image with or height at <= 640
* 2: image with or height at <= 320
* 3: thumbnail 160x160
* 4: Profile image at 300x300
* 5: Profile image at 80x80
* 6: Profile image at 48x48
An image used as profile image has only scale 4-6, other images only 0-3
#### Return values
json:
```json
{
"id": "photo id",
"created": "date(YYYY-MM-DD HH:MM:SS)",
"edited": "date(YYYY-MM-DD HH:MM:SS)",
"title": "photo title",
"desc": "photo description",
"album": "album name",
"filename": "original file name",
"type": "mime type",
"height": "number",
"width": "number",
"profile": "1 if is profile photo",
"link": {
"<scale>": "url to image",
...
},
// if 'scale' is set
"datasize": "size in byte",
"data": "base64 encoded image data"
}
```
xml:
```xml
<photo>
<id>photo id</id>
<created>date(YYYY-MM-DD HH:MM:SS)</created>
<edited>date(YYYY-MM-DD HH:MM:SS)</edited>
<title>photo title</title>
<desc>photo description</desc>
<album>album name</album>
<filename>original file name</filename>
<type>mime type</type>
<height>number</height>
<width>number</width>
<profile>1 if is profile photo</profile>
<links type="array">
<link type="mime type" scale="scale number" href="image url"/>
...
</links>
</photo>
```
### GET api/friendica/photos/list
Returns the API user's [Photo List Items](help/API-Entities#Photo+List+Item).
#### Return values
json:
```json
[
{
"id": "resource_id",
"album": "album name",
"filename": "original file name",
"type": "image mime type",
"thumb": "url to thumb sized image"
},
...
]
```
xml:
```xml
<photos type="array">
<photo id="resource_id"
album="album name"
filename="original file name"
type="image mime type">
"url to thumb sized image"
</photo>
...
</photos>
```
### POST api/friendica/photo/create
Alias of [`api/friendica/photo/update`](#POST+api%2Ffriendica%2Fphoto%2Fupdate)
### POST api/friendica/photo/update
Saves data for the scales 0-2 to database (see above for scale description).
Call adds non-public entries to items table to enable authenticated contacts to comment/like the photo.
Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited group.
Currently it is best to inform user that updating rights is not the right way to do this, and offer a solution to add photo as a new photo with the new rights instead.
#### Parameters
* `photo_id` (optional): if specified the photo with this id will be updated
* `media` (optional): image data as base64, only optional if photo_id is specified (new upload must have media)
* `desc` (optional): description for the photo, updated when photo_id is specified
* `album`: name of the album to be deleted (always necessary)
* `album_new` (optional): can be used to change the album of a single photo if photo_id is specified
* `allow_cid`/`allow_gid`/`deny_cid`/`deny_gid` (optional):
- on create: empty string or omitting = public photo, specify in format ```<x><y><z>``` for private photo
- on update: keys need to be present with empty values for changing a private photo to public
#### Return values
On success:
* new photo uploaded: JSON return with photo data (see [GET api/friendica/photo](#GET+api%2Ffriendica%2Fphoto))
* photo updated - changed photo data: JSON return with photo data (see [GET api/friendica/photo](#GET+api%2Ffriendica%2Fphoto))
* photo updated - changed info: JSON return `{"result": "updated", "message":"Image id 'xyz' has been updated."}`
* photo updated - nothing changed: JSON return `{"result": "cancelled","message": "Nothing to update for image id 'xyz'."}`
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "no media data submitted", "photo not available", "acl data invalid"
* 500 INTERNALSERVERERROR: "image size exceeds PHP config settings, file was rejected by server",
"image size exceeds Friendica Config setting (uploaded size: x)",
"unable to process image data",
"image upload failed",
"unknown error - uploading photo failed, see Friendica log for more information",
"unknown error - update photo entry in database failed",
"unknown error - this error on uploading or updating a photo should never happen"
### DELETE api/friendica/photo/delete
Deletes a single image with the specified id, is not reversible -> ensure that client is asking user for being sure to do this
Sets item table entries for this photo to deleted = 1.
#### Parameters
* `photo_id`: id of the photo to be deleted
#### Return values
On success:
* JSON return
```json
{
"result": "deleted",
"message": "photo with id 'xyz' has been deleted from server."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no photo_id specified", "photo not available"
* 500 INTERNALSERVERERROR: "unknown error on deleting photo", "problem with deleting items occurred"
---
### POST/DELETE api/friendica/photoalbum/delete
Deletes all images with the specified album name, is not reversible -> ensure that client is asking user for being sure to do this.
#### Parameters
* `album`: name of the album to be deleted
#### Return values
On success:
* JSON return
```json
{
"result": "deleted",
"message": "album 'xyz' with all containing photos has been deleted."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "album not available"
* 500 INTERNALSERVERERROR: "problem with deleting item occured", "unknown error - deleting from database failed"
### POST/PUT api/friendica/photoalbum/update
Changes the album name to album_new for all photos in album.
#### Parameters
* `album`: name of the album to be updated
* `album_new`: new name of the album
#### Return values
On success:
* JSON return
```json
{
"result": "updated",
"message":"album 'abc' with all containing photos has been renamed to 'xyz'."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "no new albumname specified", "album not available"
* 500 INTERNALSERVERERROR: "unknown error - updating in database failed"
---
### GET api/friendica/profile/show
Returns the [Profile](help/API-Entities#Profile) data of all profiles or a single profile of the authenticated user.
#### Parameters
* `profile_id` (optional): id of the profile to be returned. If omitted all profiles are returned by default.
#### Return values
On success: Array of:
* `multi_profiles`: true if user has activated multi_profiles
* `global_dir`: URL of the global directory set in server settings
* `friendica_owner`: user data of the authenticated user
* `profiles`: array of the profile data
On error:
HTTP 403 Forbidden: when no authentication was provided
HTTP 400 Bad Request: if given profile_id is not in the database or is not assigned to the authenticated user
General description of profile data in API returns:
---
### GET api/friendica/remoteauth
Similar as /redir, redirects to `url` after DFRN authentication.
#### Parameters
- `c_url`: url of remote contact to auth to
- `url`: string, url to redirect after auth
## Deprecated endpoints
- POST api/statuses/mediap

81
doc/API-GNU-Social.md Normal file
View file

@ -0,0 +1,81 @@
# GNU Social API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in [the official GNU Social Twitter-like API reference](https://gnusocial.net/doc/twitterapi).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Friendica API entities](help/API-Entities).
## Implemented endpoints
- GET api/account/rate_limit_status
- POST api/account/update_profile_image
- GET api/account/verify_credentials
- GET api/direct_messages
- POST/DELETE api/direct_messages/destroy
- POST api/direct_messages/new
- GET api/direct_messages/sent
- GET api/favorites
- POST api/favorites/create/:id
- POST api/favorites/destroy/:id
- GET api/followers/ids
- POST api/friendships/destroy
- GET api/friends/ids
- GET/POST api/help/test
- POST api/oauth/access_token
- POST api/oauth/request_token
- GET api/search
- GET api/statuses/show/:id
- POST api/statuses/destroy/:id
- GET api/statuses/followers
- GET api/statuses/friends
- GET api/statuses/friends_timeline
- GET api/statuses/friends_timeline/:username
- GET api/statuses/home_timeline
- GET api/statuses/mentions
- GET api/statuses/replies
- GET api/statuses/replies/:username
- POST api/statuses/retweet/:id
- GET api/statuses/public_timeline
- POST api/statuses/update
- GET api/statuses/user_timeline
- GET api/users/show
## Non-implemented endpoints
- statuses/retweeted_to_me
- statuses/retweeted_by_me
- statuses/retweets_of_me
- friendships/create
- friendships/exists
- friendships/show
- account/end_session
- account/update_delivery_device
- account/update_profile_background_image
- notifications/follow
- notifications/leave
- blocks/create
- blocks/destroy
- blocks/exists
- blocks/blocking
- oauth/authorize
- statusnet/groups/timeline
- statusnet/groups/show
- statusnet/groups/create
- statusnet/groups/join
- statusnet/groups/leave
- statusnet/groups/list
- statusnet/groups/list_all
- statusnet/groups/membership
- statusnet/groups/is_member
- statusnet/tags/timeline
- statusnet/media/upload
- statusnet/config

24
doc/API-Mastodon.md Normal file
View file

@ -0,0 +1,24 @@
# Mastodon API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in [the official Mastodon API reference](https://docs.joinmastodon.org/api/).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/api/entities/).
## Implemented endpoints
- [GET /api/v1/follow_requests](https://docs.joinmastodon.org/api/rest/follow-requests/#get-api-v1-follow-requests)
## Non-implemented endpoints
- [POST /api/v1/follow_requests/:id/authorize](https://docs.joinmastodon.org/api/rest/follow-requests/#post-api-v1-follow-requests-id-authorize)
- [POST /api/v1/follow_requests/:id/reject](https://docs.joinmastodon.org/api/rest/follow-requests/#post-api-v1-follow-requests-id-reject)

298
doc/API-Twitter.md Normal file
View file

@ -0,0 +1,298 @@
# Twitter API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in the [official Twitter API reference](https://developer.twitter.com/en/docs/api-reference-index).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Friendica API entities](help/API-Entities).
## Different behaviour
* `screen_name`: The nick name in Friendica is only unique in each network but not for all networks. The users are searched in the following priority: Friendica, StatusNet/GNU Social, Diaspora, pump.io, Twitter. If no contact was found by this way, then the first contact is taken.
* `include_entities`: Default is "false". If set to "true" then the plain text is formatted so that links are having descriptions.
## Friendica-specific return values
* `cid`: Contact id of the user (important for "contact_allow" and "contact_deny")
* `network`: network of the user
## Unsupported parameters
* `cursor`
* `trim_user`
* `contributor_details`
* `place_id`
* `display_coordinates`
* `include_rts`: To-Do
* `include_my_retweet`: Retweets in Friendica are implemented in a different way
## Implemented endpoints
- [POST api/oauth/access_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token)
- Unsupported parameters:
- `x_auth_password`
- `x_auth_username`
- `x_auth_mode`
- [POST api/oauth/request_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/request_token)
- Unsupported parameter:
- `x_auth_access_type`
- [GET api/account/verify_credentials](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials)
- Unsupported parameter:
- `include_email`
- [POST api/account/update_profile](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile)
- Unsupported parameters:
- `url`
- `location`
- `profile_link_color`
- `include_entities`
- `skip_status`
- [POST api/account/update_profile_image](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image)
- Additional parameter:
- `profile_id` (optional): Numerical id of the profile for which the image should be used, default is changing the default profile.
- [POST api/statuses/update](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update)
- Unsupported parameter:
- `display_coordinates`
- [POST api/statuses/update_with_media (deprecated)](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update_with_media)
- [POST api/media/upload](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload)
- Additional return value:
- `image.friendica_preview_url`: image preview url
- [POST api/media/metadata/create](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create)
- [GET api/users/show](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show)
- [GET api/users/search](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search)
- Unsupported parameters:
- `page`
- `count`
- `include_entities`
- [GET api/users/lookup](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup)
- Unsupported parameters:
- `screen_name`
- `include_entities`
- [GET api/search/tweets](https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets)
- Unsupported parameters:
- `geocode`
- `lang`
- `locale`
- `result_type`
- `until`
- `include_entities`
- [GET api/saved_searches/list](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-saved_searches-list)
- [GET api/statuses/home_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline)
- Alias: `GET api/statuses/friends_timeline`
- [GET api/statuses/user_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline)
- [GET api/statuses/mentions (deprecated)](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline)
- [GET api/statuses/show/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id)
- [POST api/statuses/retweet/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id)
- [POST api/statuses/destroy/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-destroy-id)
- [GET api/statuses/followers (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list)
- Alias: `GET api/statuses/friends`
- [GET api/favorites (deprecated)](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list)
- Unsupported parameters:
- `user_id`: Favorites aren't returned for other users than self
- `screen_name`: Favorites aren't returned for other users than self
- [POST api/favorites/create](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create)
- [POST api/favorites/destroy](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-destroy)
- [GET api/lists/list](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list)
- [GET api/lists/ownerships](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships)
- Unsupported parameters:
- `slug`
- `owner_screen_name`
- `owner_id`
- `include_entities`
- [GET api/lists/statuses](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-statuses)
- Unsupported parameters:
- `screen_name`
- `count`
- [GET api/lists/subscriptions](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscriptions)
- [POST api/lists/update](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update)
- Unsupported parameters:
- `slug`
- `name`
- `mode`
- `description`
- `owner_screen_name`
- `owner_id`
- [POST api/lists/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create)
- Unsupported parameters:
- `mode`
- `description`
- [POST api/lists/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy)
- Unsupported parameters:
- `owner_screen_name`
- `owner_id`
- `slug`
- [GET api/blocks/list](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-list)
- [GET api/friendships/incoming](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-incoming)
- Unsupported parameters
- `stringify_ids`
- [GET api/followers/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids)
- Unsupported parameters:
- `user_id`: Relationships aren't returned for other users than self
- `screen_name`: Relationships aren't returned for other users than self
- [GET api/friends/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids)
- Unsupported parameters:
- `user_id`: Relationships aren't returned for other users than self
- `screen_name`: Relationships aren't returned for other users than self
- [POST api/friendships/destroy](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-destroy)
## Non-implemented endpoints
- [GET oauth/authenticate](https://developer.twitter.com/en/docs/basics/authentication/api-reference/authenticate)
- [GET oauth/authorize](https://developer.twitter.com/en/docs/basics/authentication/api-reference/authorize)
- [POST oauth/invalidate_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_access_token)
- [POST oauth2/invalidate_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_bearer_token)
- [POST oauth2/token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/token)
- [GET lists/members](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members)
- [GET lists/members/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members-show)
- [GET lists/memberships](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-memberships)
- [GET lists/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-show)
- [GET lists/subscribers](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers)
- [GET lists/subscribers/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers-show)
- [POST lists/members/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create)
- [POST lists/members/create_all](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create_all)
- [POST lists/members/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy)
- [POST lists/members/destroy_all](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy_all)
- [POST lists/subscribers/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-create)
- [POST lists/subscribers/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-destroy)
- [GET followers/list](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list)
- [GET friends/list](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list)
- [GET friendships/lookup](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-lookup)
- [GET friendships/no_retweets/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-no_retweets-ids)
- [GET friendships/outgoing](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-outgoing)
- [GET friendships/show](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-show)
- [GET users/suggestions (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions)
- [GET users/suggestions/:slug (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug)
- [GET users/suggestions/:slug/members (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug-members)
- [POST friendships/create](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-create)
- [POST friendships/update](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-update)
- [GET account/settings](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-settings)
- [GET saved_searches/show/:id](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-saved_searches-show-id)
- [GET users/profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-users-profile_banner)
- [POST account/remove_profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-remove_profile_banner)
- [POST account/settings](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-settings)
- [POST account/update_profile_background_image (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_background_image)
- [POST account/update_profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_banner)
- [POST saved_searches/create](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-saved_searches-create)
- [POST saved_searches/destroy/:id](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-saved_searches-destroy-id)
- [GET blocks/ids](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-ids)
- [GET mutes/users/ids](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-ids)
- [GET mutes/users/list](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-list)
- [POST blocks/create](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-create)
- [POST blocks/destroy](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-destroy)
- [POST mutes/users/create](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create)
- [POST mutes/users/destroy](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-destroy)
- [POST users/report_spam](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-users-report_spam)
- [GET collections/entries](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-entries)
- [GET collections/list](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-list)
- [GET collections/show](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-show)
- [POST collections/create](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-create)
- [POST collections/destroy](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-destroy)
- [POST collections/entries/add](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-add)
- [POST collections/entries/curate](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-curate)
- [POST collections/entries/move](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-move)
- [POST collections/entries/remove](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-remove)
- [POST collections/update](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-update)
- [POST statuses/filter](https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter)
- [GET statuses/mentions_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline)
- [GET favorites/list](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list)
- [GET statuses/lookup](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-lookup)
- [GET statuses/oembed](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-oembed)
- [GET statuses/retweeters/ids](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweeters-ids)
- [GET statuses/retweets/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets-id)
- [GET statuses/retweets_of_me](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets_of_me)
- [POST statuses/unretweet/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-unretweet-id)
- [GET statuses/sample](https://developer.twitter.com/en/docs/tweets/sample-realtime/api-reference/get-statuses-sample)
- [GET compliance/firehose](https://developer.twitter.com/en/docs/tweets/compliance/api-reference/compliance-firehose)
- [DELETE custom_profiles/destroy.json](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/delete-profile)
- [GET custom_profiles/:id](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/get-profile)
- [GET custom_profiles/list](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/get-profile-list)
- [POST custom_profiles/new.json](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/new-profile)
- [DELETE direct_messages/events/destroy](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message-event)
- [GET direct_messages/events/list](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/list-events)
- [GET direct_messages/events/show](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-event)
- [POST direct_messages/events/new (message_create)](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-event)
- [POST direct_messages/indicate_typing](https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-typing-indicator)
- [POST direct_messages/mark_read](https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-read-receipt)
- [DELETE direct_messages/welcome_messages/destroy](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/delete-welcome-message)
- [DELETE direct_messages/welcome_messages/rules/destroy](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/delete-welcome-message-rule)
- [PUT direct_messages/welcome_messages/update](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/update-welcome-message)
- [GET direct_messages/welcome_messages/list](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/list-welcome-messages)
- [GET direct_messages/welcome_messages/rules/list](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/list-welcome-message-rules)
- [GET direct_messages/welcome_messages/rules/show](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/get-welcome-message-rule)
- [GET direct_messages/welcome_messages/show](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/get-welcome-message)
- [POST direct_messages/welcome_messages/new](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/new-welcome-message)
- [POST direct_messages/welcome_messages/rules/new](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/new-welcome-message-rule)
- [GET media/upload (STATUS)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/get-media-upload-status)
- [POST media/subtitles/create](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-subtitles-create)
- [POST media/subtitles/delete](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-subtitles-delete)
- [POST media/upload (APPEND)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-append)
- [POST media/upload (FINALIZE)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-finalize)
- [POST media/upload (INIT)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init)
- [GET trends/available](https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available)
- [GET trends/closest](https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest)
- [GET trends/place](https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place)
- [GET geo/id/:place_id](https://developer.twitter.com/en/docs/geo/place-information/api-reference/get-geo-id-place_id)
- [GET geo/reverse_geocode](https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-reverse_geocode)
- [GET geo/search](https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-search)

View file

@ -99,7 +99,7 @@ See Also
* [Profiles](help/Profiles) * [Profiles](help/Profiles)
* [Global Directory](help/Making-Friends#1_1) * [Global Directory](help/Making-Friends#The+Directories)
* [Groups and Privacy](help/Groups-and-Privacy) * [Groups and Privacy](help/Groups-and-Privacy)

View file

@ -12,7 +12,7 @@ This kind of functionality requires a bit more of the host system than the typic
Not every PHP/MySQL hosting provider will be able to support Friendica. Not every PHP/MySQL hosting provider will be able to support Friendica.
Many will. Many will.
But **please** review the [requirements](#1_2_1) and confirm these with your hosting provider prior to installation. But **please** review the [requirements](#Requirements) and confirm these with your hosting provider prior to installation.
## Support ## Support
If you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues). If you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues).
@ -108,7 +108,7 @@ Create an empty database and note the access details (hostname, username, passwo
Friendica needs the permission to create and delete fields and tables in its own database. Friendica needs the permission to create and delete fields and tables in its own database.
Please check the [troubleshooting](#1_6) section if running on MySQL 5.7.17 or newer. Please check the [troubleshooting](#Troubleshooting) section if running on MySQL 5.7.17 or newer.
### Option A: Run the installer ### Option A: Run the installer

1427
doc/api.md

File diff suppressed because it is too large Load diff

View file

@ -3,15 +3,20 @@
/* Generic exception class /* Generic exception class
*/ */
use Friendica\Network\FKOAuthDataStore;
if (!class_exists('OAuthException', false)) { if (!class_exists('OAuthException', false)) {
class OAuthException extends Exception class OAuthException extends Exception
{ } {
}
} }
class OAuthConsumer class OAuthConsumer
{ {
public $key; public $key;
public $secret; public $secret;
public $callback_url;
function __construct($key, $secret, $callback_url = NULL) function __construct($key, $secret, $callback_url = NULL)
{ {
@ -39,6 +44,9 @@ class OAuthToken
/** /**
* key = the token * key = the token
* secret = the token secret * secret = the token secret
*
* @param $key
* @param $secret
*/ */
function __construct($key, $secret) function __construct($key, $secret)
{ {
@ -72,6 +80,7 @@ abstract class OAuthSignatureMethod
{ {
/** /**
* Needs to return the name of the Signature Method (ie HMAC-SHA1) * Needs to return the name of the Signature Method (ie HMAC-SHA1)
*
* @return string * @return string
*/ */
abstract public function get_name(); abstract public function get_name();
@ -81,15 +90,17 @@ abstract class OAuthSignatureMethod
* NOTE: The output of this function MUST NOT be urlencoded. * NOTE: The output of this function MUST NOT be urlencoded.
* the encoding is handled in OAuthRequest when the final * the encoding is handled in OAuthRequest when the final
* request is serialized * request is serialized
*
* @param OAuthRequest $request * @param OAuthRequest $request
* @param OAuthConsumer $consumer * @param OAuthConsumer $consumer
* @param OAuthToken $token * @param OAuthToken $token
* @return string * @return string
*/ */
abstract public function build_signature($request, $consumer, $token); abstract public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token);
/** /**
* Verifies that a given signature is correct * Verifies that a given signature is correct
*
* @param OAuthRequest $request * @param OAuthRequest $request
* @param OAuthConsumer $consumer * @param OAuthConsumer $consumer
* @param OAuthToken $token * @param OAuthToken $token
@ -117,7 +128,13 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
return "HMAC-SHA1"; return "HMAC-SHA1";
} }
public function build_signature($request, $consumer, $token) /**
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @return string
*/
public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token)
{ {
$base_string = $request->get_signature_base_string(); $base_string = $request->get_signature_base_string();
$request->base_string = $base_string; $request->base_string = $base_string;
@ -156,8 +173,13 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod
* *
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this! * OAuthRequest handles this!
*
* @param $request
* @param $consumer
* @param $token
* @return string
*/ */
public function build_signature($request, $consumer, $token) public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token)
{ {
$key_parts = array( $key_parts = array(
$consumer->secret, $consumer->secret,
@ -201,7 +223,7 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod
// Either way should return a string representation of the certificate // Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request); protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) public function build_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token)
{ {
$base_string = $request->get_signature_base_string(); $base_string = $request->get_signature_base_string();
$request->base_string = $base_string; $request->base_string = $base_string;
@ -213,7 +235,7 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod
$privatekeyid = openssl_get_privatekey($cert); $privatekeyid = openssl_get_privatekey($cert);
// Sign using the key // Sign using the key
$ok = openssl_sign($base_string, $signature, $privatekeyid); openssl_sign($base_string, $signature, $privatekeyid);
// Release the key resource // Release the key resource
openssl_free_key($privatekeyid); openssl_free_key($privatekeyid);
@ -265,6 +287,11 @@ class OAuthRequest
/** /**
* attempt to build up a request from what was passed to the server * attempt to build up a request from what was passed to the server
*
* @param string|null $http_method
* @param string|null $http_url
* @param string|null $parameters
* @return OAuthRequest
*/ */
public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL) public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL)
{ {
@ -323,8 +350,15 @@ class OAuthRequest
/** /**
* pretty much a helper function to set up the request * pretty much a helper function to set up the request
*
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @param string $http_method
* @param string $http_url
* @param array|null $parameters
* @return OAuthRequest
*/ */
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = NULL) public static function from_consumer_and_token(OAuthConsumer $consumer, OAuthToken $token, $http_method, $http_url, array $parameters = NULL)
{ {
@$parameters or $parameters = array(); @$parameters or $parameters = array();
$defaults = array( $defaults = array(
@ -374,6 +408,7 @@ class OAuthRequest
/** /**
* The request parameters, sorted and concatenated into a normalized string. * The request parameters, sorted and concatenated into a normalized string.
*
* @return string * @return string
*/ */
public function get_signable_parameters() public function get_signable_parameters()
@ -456,8 +491,11 @@ class OAuthRequest
/** /**
* builds the data one would send in a POST request * builds the data one would send in a POST request
*
* @param bool $raw
* @return array|string
*/ */
public function to_postdata($raw = false) public function to_postdata(bool $raw = false)
{ {
if ($raw) if ($raw)
return $this->parameters; return $this->parameters;
@ -467,6 +505,10 @@ class OAuthRequest
/** /**
* builds the Authorization: header * builds the Authorization: header
*
* @param string|null $realm
* @return string
* @throws OAuthException
*/ */
public function to_header($realm = null) public function to_header($realm = null)
{ {
@ -498,7 +540,7 @@ class OAuthRequest
} }
public function sign_request($signature_method, $consumer, $token) public function sign_request(OAuthSignatureMethod $signature_method, $consumer, $token)
{ {
$this->set_parameter( $this->set_parameter(
"oauth_signature_method", "oauth_signature_method",
@ -509,7 +551,7 @@ class OAuthRequest
$this->set_parameter("oauth_signature", $signature, false); $this->set_parameter("oauth_signature", $signature, false);
} }
public function build_signature($signature_method, $consumer, $token) public function build_signature(OAuthSignatureMethod $signature_method, $consumer, $token)
{ {
$signature = $signature_method->build_signature($this, $consumer, $token); $signature = $signature_method->build_signature($this, $consumer, $token);
return $signature; return $signature;
@ -536,16 +578,18 @@ class OAuthServer
{ {
protected $timestamp_threshold = 300; // in seconds, five minutes protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine protected $version = '1.0'; // hi blaine
/** @var OAuthSignatureMethod[] */
protected $signature_methods = array(); protected $signature_methods = array();
/** @var FKOAuthDataStore */
protected $data_store; protected $data_store;
function __construct($data_store) function __construct(FKOAuthDataStore $data_store)
{ {
$this->data_store = $data_store; $this->data_store = $data_store;
} }
public function add_signature_method($signature_method) public function add_signature_method(OAuthSignatureMethod $signature_method)
{ {
$this->signature_methods[$signature_method->get_name()] = $this->signature_methods[$signature_method->get_name()] =
$signature_method; $signature_method;
@ -556,8 +600,12 @@ class OAuthServer
/** /**
* process a request_token request * process a request_token request
* returns the request token on success * returns the request token on success
*
* @param OAuthRequest $request
* @return OAuthToken|null
* @throws OAuthException
*/ */
public function fetch_request_token(&$request) public function fetch_request_token(OAuthRequest $request)
{ {
$this->get_version($request); $this->get_version($request);
@ -578,8 +626,12 @@ class OAuthServer
/** /**
* process an access_token request * process an access_token request
* returns the access token on success * returns the access token on success
*
* @param OAuthRequest $request
* @return object
* @throws OAuthException
*/ */
public function fetch_access_token(&$request) public function fetch_access_token(OAuthRequest $request)
{ {
$this->get_version($request); $this->get_version($request);
@ -599,8 +651,12 @@ class OAuthServer
/** /**
* verify an api call, checks all the parameters * verify an api call, checks all the parameters
*
* @param OAuthRequest $request
* @return array
* @throws OAuthException
*/ */
public function verify_request(&$request) public function verify_request(OAuthRequest $request)
{ {
$this->get_version($request); $this->get_version($request);
$consumer = $this->get_consumer($request); $consumer = $this->get_consumer($request);
@ -610,10 +666,15 @@ class OAuthServer
} }
// Internals from here // Internals from here
/** /**
* version 1 * version 1
*
* @param OAuthRequest $request
* @return string
* @throws OAuthException
*/ */
private function get_version(&$request) private function get_version(OAuthRequest $request)
{ {
$version = $request->get_parameter("oauth_version"); $version = $request->get_parameter("oauth_version");
if (!$version) { if (!$version) {
@ -629,8 +690,12 @@ class OAuthServer
/** /**
* figure out the signature with some defaults * figure out the signature with some defaults
*
* @param OAuthRequest $request
* @return OAuthSignatureMethod
* @throws OAuthException
*/ */
private function get_signature_method(&$request) private function get_signature_method(OAuthRequest $request)
{ {
$signature_method = $signature_method =
@$request->get_parameter("oauth_signature_method"); @$request->get_parameter("oauth_signature_method");
@ -656,8 +721,12 @@ class OAuthServer
/** /**
* try to find the consumer for the provided request's consumer key * try to find the consumer for the provided request's consumer key
*
* @param OAuthRequest $request
* @return OAuthConsumer
* @throws OAuthException
*/ */
private function get_consumer(&$request) private function get_consumer(OAuthRequest $request)
{ {
$consumer_key = @$request->get_parameter("oauth_consumer_key"); $consumer_key = @$request->get_parameter("oauth_consumer_key");
if (!$consumer_key) { if (!$consumer_key) {
@ -674,8 +743,14 @@ class OAuthServer
/** /**
* try to find the token for the provided request's token key * try to find the token for the provided request's token key
*
* @param OAuthRequest $request
* @param $consumer
* @param string $token_type
* @return OAuthToken|null
* @throws OAuthException
*/ */
private function get_token(&$request, $consumer, $token_type = "access") private function get_token(OAuthRequest &$request, $consumer, $token_type = "access")
{ {
$token_field = @$request->get_parameter('oauth_token'); $token_field = @$request->get_parameter('oauth_token');
$token = $this->data_store->lookup_token( $token = $this->data_store->lookup_token(
@ -692,8 +767,13 @@ class OAuthServer
/** /**
* all-in-one function to check the signature on a request * all-in-one function to check the signature on a request
* should guess the signature method appropriately * should guess the signature method appropriately
*
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken|null $token
* @throws OAuthException
*/ */
private function check_signature(&$request, $consumer, $token) private function check_signature(OAuthRequest $request, OAuthConsumer $consumer, OAuthToken $token = null)
{ {
// this should probably be in a different method // this should probably be in a different method
$timestamp = @$request->get_parameter('oauth_timestamp'); $timestamp = @$request->get_parameter('oauth_timestamp');
@ -720,6 +800,9 @@ class OAuthServer
/** /**
* check that the timestamp is new enough * check that the timestamp is new enough
*
* @param int $timestamp
* @throws OAuthException
*/ */
private function check_timestamp($timestamp) private function check_timestamp($timestamp)
{ {
@ -739,8 +822,14 @@ class OAuthServer
/** /**
* check that the nonce is not repeated * check that the nonce is not repeated
*
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @param string $nonce
* @param int $timestamp
* @throws OAuthException
*/ */
private function check_nonce($consumer, $token, $nonce, $timestamp) private function check_nonce(OAuthConsumer $consumer, OAuthToken $token, $nonce, int $timestamp)
{ {
if (!$nonce) if (!$nonce)
throw new OAuthException( throw new OAuthException(
@ -767,22 +856,22 @@ class OAuthDataStore
// implement me // implement me
} }
function lookup_token($consumer, $token_type, $token) function lookup_token(OAuthConsumer $consumer, $token_type, $token_id)
{ {
// implement me // implement me
} }
function lookup_nonce($consumer, $token, $nonce, $timestamp) function lookup_nonce(OAuthConsumer $consumer, OAuthToken $token, $nonce, int $timestamp)
{ {
// implement me // implement me
} }
function new_request_token($consumer, $callback = null) function new_request_token(OAuthConsumer $consumer, $callback = null)
{ {
// return a new token attached to this consumer // return a new token attached to this consumer
} }
function new_access_token($token, $consumer, $verifier = null) function new_access_token(OAuthToken $token, OAuthConsumer $consumer, $verifier = null)
{ {
// return a new access token attached to this consumer // return a new access token attached to this consumer
// for the user associated with this token if the request token // for the user associated with this token if the request token

View file

@ -0,0 +1,86 @@
<?php
namespace Friendica\Api\Mastodon;
use Friendica\Content\Text\BBCode;
use Friendica\Database\DBA;
use Friendica\Util\DateTimeFormat;
/**
* Class Account
*
* @see https://docs.joinmastodon.org/api/entities/#account
*/
class Account
{
/** @var string */
var $id;
/** @var string */
var $username;
/** @var string */
var $acct;
/** @var string */
var $display_name;
/** @var bool */
var $locked;
/** @var string (Datetime) */
var $created_at;
/** @var int */
var $followers_count;
/** @var int */
var $following_count;
/** @var int */
var $statuses_count;
/** @var string */
var $note;
/** @var string (URL)*/
var $url;
/** @var string (URL) */
var $avatar;
/** @var string (URL) */
var $avatar_static;
/** @var string (URL) */
var $header;
/** @var string (URL) */
var $header_static;
/** @var Emoji[] */
var $emojis;
/** @var Account|null */
var $moved = null;
/** @var Field[]|null */
var $fields = null;
/** @var bool|null */
var $bot = null;
/**
* Creates an account record from a contact record. Expects all contact table fields to be set
*
* @param array $contact
* @return Account
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function createFromContact(array $contact) {
$account = new Account();
$account->id = $contact['id'];
$account->username = $contact['nick'];
$account->acct = $contact['nick'];
$account->display_name = $contact['name'];
$account->locked = $contact['blocked'];
$account->created_at = DateTimeFormat::utc($contact['created'], DateTimeFormat::ATOM);
// No data is available from contact
$account->followers_count = 0;
$account->following_count = 0;
$account->statuses_count = 0;
$account->note = BBCode::convert($contact['about']);
$account->url = $contact['url'];
$account->avatar = $contact['avatar'];
$account->avatar_static = $contact['avatar'];
// No header picture in Friendica
$account->header = '';
$account->header_static = '';
// No custom emojis per account in Friendica
$account->emojis = [];
return $account;
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace Friendica\Api\Mastodon;
/**
* Class Emoji
*
* @see https://docs.joinmastodon.org/api/entities/#emoji
*/
class Emoji
{
/** @var string */
var $shortcode;
/** @var string (URL)*/
var $static_url;
/** @var string (URL)*/
var $url;
/** @var bool */
var $visible_in_picker;
}

View file

@ -0,0 +1,18 @@
<?php
namespace Friendica\Api\Mastodon;
/**
* Class Field
*
* @see https://docs.joinmastodon.org/api/entities/#field
*/
class Field
{
/** @var string */
var $name;
/** @var string (HTML) */
var $value;
/** @var string (Datetime)*/
var $verified_at;
}

View file

@ -0,0 +1,79 @@
<?php
namespace Friendica\Module\Api\Mastodon;
use Friendica\Api\Mastodon\Account;
use Friendica\App\BaseURL;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Module\Base\Api;
use Friendica\Network\HTTPException;
/**
* @see https://docs.joinmastodon.org/api/rest/follow-requests/
*/
class FollowRequests extends Api
{
public static function init(array $parameters = [])
{
parent::init($parameters);
self::login();
}
/**
* @param array $parameters
* @throws HTTPException\InternalServerErrorException
* @see https://docs.joinmastodon.org/api/rest/follow-requests/#get-api-v1-follow-requests
*/
public static function rawContent(array $parameters = [])
{
$since_id = $_GET['since_id'] ?? null;
$max_id = $_GET['max_id'] ?? null;
$limit = intval($_GET['limit'] ?? 40);
if (isset($since_id) && isset($max_id)) {
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` > ? AND `id` < ?', self::$current_user_id, $since_id, $max_id];
} elseif (isset($since_id)) {
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` > ?', self::$current_user_id, $since_id];
} elseif (isset($max_id)) {
$condition = ['`uid` = ? AND NOT `self` AND `pending` AND `id` < ?', self::$current_user_id, $max_id];
} else {
$condition = ['`uid` = ? AND NOT `self` AND `pending`', self::$current_user_id];
}
$count = DBA::count('contact', $condition);
$contacts = Contact::selectToArray(
[],
$condition,
['order' => ['id' => 'DESC'], 'limit' => $limit]
);
$return = [];
foreach ($contacts as $contact) {
$account = Account::createFromContact($contact);
$return[] = $account;
}
$base_query = [];
if (isset($_GET['limit'])) {
$base_query['limit'] = $limit;
}
/** @var BaseURL $BaseURL */
$BaseURL = self::getClass(BaseURL::class);
$links = [];
if ($count > $limit) {
$links[] = '<' . $BaseURL->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['max_id' => $contacts[count($contacts) - 1]['id']]) . '>; rel="next"';
}
$links[] = '<' . $BaseURL->get() . '/api/v1/follow_requests?' . http_build_query($base_query + ['since_id' => $contacts[0]['id']]) . '>; rel="prev"';
header('Link: ' . implode(', ', $links));
System::jsonExit($return);
}
}

105
src/Module/Base/Api.php Normal file
View file

@ -0,0 +1,105 @@
<?php
namespace Friendica\Module\Base;
use Friendica\App\Arguments;
use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Network\HTTPException;
require_once __DIR__ . '/../../../include/api.php';
class Api extends BaseModule
{
/**
* @var string json|xml|rss|atom
*/
protected static $format = 'json';
/**
* @var bool|int
*/
protected static $current_user_id;
public static function init(array $parameters = [])
{
$Arguments = self::getClass(Arguments::class);
if (substr($Arguments->getQueryString(), -4) === '.xml') {
self::$format = 'xml';
}
if (substr($Arguments->getQueryString(), -4) === '.rss') {
self::$format = 'rss';
}
if (substr($Arguments->getQueryString(), -4) === '.atom') {
self::$format = 'atom';
}
}
public static function post(array $parameters = [])
{
if (!api_user()) {
throw new HTTPException\UnauthorizedException(L10n::t('Permission denied.'));
}
$a = self::getApp();
if (!empty($a->user['uid']) && $a->user['uid'] != api_user()) {
throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
}
}
/**
* Log in user via OAuth1 or Simple HTTP Auth.
* Simple Auth allow username in form of <pre>user@server</pre>, ignoring server part
*
* @brief Login API user
*
* @throws HTTPException\ForbiddenException
* @throws HTTPException\UnauthorizedException
* @throws HTTPException\InternalServerErrorException
* @hook 'authenticate'
* array $addon_auth
* 'username' => username from login form
* 'password' => password from login form
* 'authenticated' => return status,
* 'user_record' => return authenticated user record
*/
protected static function login()
{
api_login(self::getApp());
self::$current_user_id = api_user();
}
/**
* @brief Get user info array.
*
* @param int|string $contact_id Contact ID or URL
* @return array|bool
* @throws HTTPException\BadRequestException
* @throws HTTPException\InternalServerErrorException
* @throws HTTPException\UnauthorizedException
* @throws \ImagickException
*/
protected static function getUser($contact_id = null)
{
return api_get_user(self::getApp(), $contact_id);
}
protected static function format($root_element, $data)
{
switch (self::$format) {
case "atom":
case "rss":
case "xml":
$ret = api_create_xml($data, $root_element);
break;
case "json":
default:
$ret = $data;
break;
}
return $ret;
}
}

View file

@ -65,10 +65,11 @@ class Help extends BaseModule
$lastLevel = 1; $lastLevel = 1;
$idNum = [0, 0, 0, 0, 0, 0, 0]; $idNum = [0, 0, 0, 0, 0, 0, 0];
foreach ($lines as &$line) { foreach ($lines as &$line) {
if (substr($line, 0, 2) == "<h") { $matches = [];
$level = substr($line, 2, 1); foreach ($lines as &$line) {
if ($level != "r") { if (preg_match('#<h([1-6])>([^<]+?)</h\1>#i', $line, $matches)) {
$level = intval($level); $level = $matches[1];
$anchor = urlencode($matches[2]);
if ($level < $lastLevel) { if ($level < $lastLevel) {
for ($k = $level; $k < $lastLevel; $k++) { for ($k = $level; $k < $lastLevel; $k++) {
$toc .= "</ul></li>"; $toc .= "</ul></li>";
@ -84,10 +85,13 @@ class Help extends BaseModule
} }
$idNum[$level] ++; $idNum[$level] ++;
$href = $a->getBaseURL() . "/help/{$filename}#{$anchor}";
$toc .= "<li><a href=\"{$href}\">" . strip_tags($line) . "</a></li>";
$id = implode("_", array_slice($idNum, 1, $level)); $id = implode("_", array_slice($idNum, 1, $level));
$href = $a->getBaseURL() . "/help/{$filename}#{$id}"; $line = "<a name=\"{$id}\"></a>" . $line;
$toc .= "<li><a href='{$href}'>" . strip_tags($line) . "</a></li>"; $line = "<a name=\"{$anchor}\"></a>" . $line;
$line = "<a name='{$id}'></a>" . $line;
$lastLevel = $level; $lastLevel = $level;
} }
} }

View file

@ -12,6 +12,7 @@ namespace Friendica\Network;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Util\Strings;
use OAuthConsumer; use OAuthConsumer;
use OAuthDataStore; use OAuthDataStore;
use OAuthToken; use OAuthToken;
@ -26,15 +27,16 @@ class FKOAuthDataStore extends OAuthDataStore
{ {
/** /**
* @return string * @return string
* @throws \Exception
*/ */
private static function genToken() private static function genToken()
{ {
return Friendica\Util\Strings::getRandomHex(32); return Strings::getRandomHex(32);
} }
/** /**
* @param string $consumer_key key * @param string $consumer_key key
* @return mixed * @return OAuthConsumer|null
* @throws \Exception * @throws \Exception
*/ */
public function lookup_consumer($consumer_key) public function lookup_consumer($consumer_key)
@ -52,17 +54,17 @@ class FKOAuthDataStore extends OAuthDataStore
} }
/** /**
* @param string $consumer consumer * @param OAuthConsumer $consumer
* @param string $token_type type * @param string $token_type
* @param string $token token * @param string $token_id
* @return mixed * @return OAuthToken|null
* @throws \Exception * @throws \Exception
*/ */
public function lookup_token($consumer, $token_type, $token) public function lookup_token(OAuthConsumer $consumer, $token_type, $token_id)
{ {
Logger::log(__function__ . ":" . $consumer . ", " . $token_type . ", " . $token); Logger::log(__function__ . ":" . $consumer . ", " . $token_type . ", " . $token_id);
$s = DBA::select('tokens', ['id', 'secret', 'scope', 'expires', 'uid'], ['client_id' => $consumer->key, 'scope' => $token_type, 'id' => $token]); $s = DBA::select('tokens', ['id', 'secret', 'scope', 'expires', 'uid'], ['client_id' => $consumer->key, 'scope' => $token_type, 'id' => $token_id]);
$r = DBA::toArray($s); $r = DBA::toArray($s);
if (DBA::isResult($r)) { if (DBA::isResult($r)) {
@ -77,14 +79,14 @@ class FKOAuthDataStore extends OAuthDataStore
} }
/** /**
* @param string $consumer consumer * @param OAuthConsumer $consumer
* @param string $token token * @param OAuthToken $token
* @param string $nonce nonce * @param string $nonce
* @param string $timestamp timestamp * @param int $timestamp
* @return mixed * @return mixed
* @throws \Exception * @throws \Exception
*/ */
public function lookup_nonce($consumer, $token, $nonce, $timestamp) public function lookup_nonce(OAuthConsumer $consumer, OAuthToken $token, $nonce, int $timestamp)
{ {
$token = DBA::selectFirst('tokens', ['id', 'secret'], ['client_id' => $consumer->key, 'id' => $nonce, 'expires' => $timestamp]); $token = DBA::selectFirst('tokens', ['id', 'secret'], ['client_id' => $consumer->key, 'id' => $nonce, 'expires' => $timestamp]);
if (DBA::isResult($token)) { if (DBA::isResult($token)) {
@ -95,12 +97,12 @@ class FKOAuthDataStore extends OAuthDataStore
} }
/** /**
* @param string $consumer consumer * @param OAuthConsumer $consumer
* @param string $callback optional, default null * @param string $callback
* @return mixed * @return OAuthToken|null
* @throws \Exception * @throws \Exception
*/ */
public function new_request_token($consumer, $callback = null) public function new_request_token(OAuthConsumer $consumer, $callback = null)
{ {
Logger::log(__function__ . ":" . $consumer . ", " . $callback); Logger::log(__function__ . ":" . $consumer . ", " . $callback);
$key = self::genToken(); $key = self::genToken();
@ -131,13 +133,13 @@ class FKOAuthDataStore extends OAuthDataStore
} }
/** /**
* @param string $token token * @param OAuthToken $token token
* @param string $consumer consumer * @param OAuthConsumer $consumer consumer
* @param string $verifier optional, defult null * @param string $verifier optional, defult null
* @return object * @return OAuthToken
* @throws HTTPException\InternalServerErrorException * @throws \Exception
*/ */
public function new_access_token($token, $consumer, $verifier = null) public function new_access_token(OAuthToken $token, OAuthConsumer $consumer, $verifier = null)
{ {
Logger::log(__function__ . ":" . $token . ", " . $consumer . ", " . $verifier); Logger::log(__function__ . ":" . $token . ", " . $consumer . ", " . $verifier);

View file

@ -27,6 +27,12 @@ return [
'/recovery' => [Module\TwoFactor\Recovery::class, [R::GET, R::POST]], '/recovery' => [Module\TwoFactor\Recovery::class, [R::GET, R::POST]],
], ],
'/api' => [
'/v1' => [
'/follow_requests' => [Module\Api\Mastodon\FollowRequests::class, [R::GET ]],
],
],
'/admin' => [ '/admin' => [
'[/]' => [Module\Admin\Summary::class, [R::GET]], '[/]' => [Module\Admin\Summary::class, [R::GET]],