mirror of
https://github.com/friendica/friendica
synced 2024-12-23 14:00:15 +00:00
Merge branch 'develop' into mastodon-timeline-temporal-paging
This commit is contained in:
commit
6ffd3a3f8c
45 changed files with 798 additions and 138 deletions
|
@ -1,7 +1,7 @@
|
||||||
codecov:
|
codecov:
|
||||||
branch: develop
|
branch: develop
|
||||||
ci:
|
ci:
|
||||||
- drone.friendi.ca
|
- ci.friendi.ca
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
precision: 2
|
precision: 2
|
||||||
|
|
|
@ -6,9 +6,27 @@ root = true
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
trim_trailing_whitespaces = true
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
quote_type = single
|
quote_type = single
|
||||||
|
max_line_length = off
|
||||||
|
|
||||||
[*.js]
|
[*.js]
|
||||||
quote_type = double
|
quote_type = double
|
||||||
|
ij_javascript_use_double_quotes = true
|
||||||
|
|
||||||
|
[*.yml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.xml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[composer.json]
|
||||||
|
indent_style = tab
|
||||||
|
|
|
@ -132,7 +132,13 @@
|
||||||
"test": "phpunit",
|
"test": "phpunit",
|
||||||
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
|
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
|
||||||
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
|
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
|
||||||
"cs:check": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"],
|
"cs:check": [
|
||||||
"cs:fix": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"]
|
"@cs:install",
|
||||||
|
"bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"
|
||||||
|
],
|
||||||
|
"cs:fix": [
|
||||||
|
"@cs:install",
|
||||||
|
"bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -908,6 +908,13 @@ Identical to [the Twitter Media Object](https://developer.twitter.com/en/docs/tw
|
||||||
<td>Resource ID (32 hex chars)</td>
|
<td>Resource ID (32 hex chars)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>media-id</code></td>
|
||||||
|
<td>String (Integer) </td>
|
||||||
|
<td>ID used for attaching images to a Mastodon Post Status</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>created</code></td>
|
<td><code>created</code></td>
|
||||||
<td>String (Date)</td>
|
<td>String (Date)</td>
|
||||||
|
@ -1001,6 +1008,14 @@ Mutually exclusive with <code>data</code> <code>datasize</code>.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>scales</code></td>
|
||||||
|
<td>Array of Photo Scales</td>
|
||||||
|
<td>
|
||||||
|
List of the various resized versions of the Photo
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>datasize</code></td>
|
<td><code>datasize</code></td>
|
||||||
<td>Integer</td>
|
<td>Integer</td>
|
||||||
|
@ -1040,6 +1055,58 @@ Mutually exclusive with <code>link</code>.
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
## Photo Scale
|
||||||
|
|
||||||
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Attribute</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th align="center">Nullable</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>id</code></td>
|
||||||
|
<td>String (Integer)</td>
|
||||||
|
<td>Row ID of this photo scale</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>scale</code></td>
|
||||||
|
<td>Integer</td>
|
||||||
|
<td>Scale number</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>link</code></td>
|
||||||
|
<td>String (URL)</td>
|
||||||
|
<td>URL to this scale's image</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>height</code></td>
|
||||||
|
<td>Integer</td>
|
||||||
|
<td>Image height in pixels</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>width</code></td>
|
||||||
|
<td>Integer</td>
|
||||||
|
<td>Image width in pixels</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>size</code></td>
|
||||||
|
<td>Integer</td>
|
||||||
|
<td>Image size in bytes</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## Photo List Item
|
## Photo List Item
|
||||||
|
|
||||||
<table class="table table-condensed table-striped table-bordered">
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
|
@ -1103,6 +1170,40 @@ Mutually exclusive with <code>link</code>.
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
## Photo Album
|
||||||
|
|
||||||
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Attribute</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>name</code></td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>The name of the photo album</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>created</code></td>
|
||||||
|
<td>String (Date)</td>
|
||||||
|
<td>The creation date of the album. Format <code>YYYY-MM-DD HH:MM:SS</code></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>count</code></td>
|
||||||
|
<td>Integer</td>
|
||||||
|
<td>The number of images in the album</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
## Private message
|
## Private message
|
||||||
|
|
||||||
<table class="table table-condensed table-striped table-bordered">
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
|
|
|
@ -665,8 +665,8 @@ On success:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"result": "updated",
|
"result": "updated",
|
||||||
"message":"album 'abc' with all containing photos has been renamed to 'xyz'."
|
"message":"album 'abc' with all containing photos has been renamed to 'xyz'."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -676,8 +676,92 @@ On error:
|
||||||
* 400 BADREQUEST: "no albumname specified", "no new albumname specified", "album not available"
|
* 400 BADREQUEST: "no albumname specified", "no new albumname specified", "album not available"
|
||||||
* 500 INTERNALSERVERERROR: "unknown error - updating in database failed"
|
* 500 INTERNALSERVERERROR: "unknown error - updating in database failed"
|
||||||
|
|
||||||
|
### GET api/friendica/photoalbums
|
||||||
|
|
||||||
|
Get a list of photo albums for the user
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
None
|
||||||
|
#### Return values
|
||||||
|
|
||||||
|
On success a list of photo album objects:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Wall Photos",
|
||||||
|
"created": "2023-01-22 02:03:19",
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Profile photos",
|
||||||
|
"created": "2022-11-20 14:40:06",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET api/friendica/photoalbum
|
||||||
|
|
||||||
|
Get a list of images in a photo album
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
* `album` (Required): name of the album to be deleted
|
||||||
|
* `limit` (Optional): Maximum number of items to get, defaults to 50, max 500
|
||||||
|
* `offset`(Optional): Offset in results to page through total items, defaults to 0
|
||||||
|
* `latest_first` (Optional): Reverse the order so the most recent images are first, defaults to false
|
||||||
|
|
||||||
|
#### Return values
|
||||||
|
|
||||||
|
On success:
|
||||||
|
|
||||||
|
* JSON return with the list of Photo items
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
`https://<server>/api/friendica/photoalbum?album=Wall Photos&limit=10&offset=2`
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"created": "2023-02-14 14:31:06",
|
||||||
|
"edited": "2023-02-14 14:31:14",
|
||||||
|
"title": "",
|
||||||
|
"desc": "",
|
||||||
|
"album": "Wall Photos",
|
||||||
|
"filename": "image.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"height": 835,
|
||||||
|
"width": 693,
|
||||||
|
"datasize": 119523,
|
||||||
|
"profile": 0,
|
||||||
|
"allow_cid": "",
|
||||||
|
"deny_cid": "",
|
||||||
|
"allow_gid": "",
|
||||||
|
"deny_gid": "",
|
||||||
|
"id": "899184972463eb9b2ae3dc2580502826",
|
||||||
|
"scale": 0,
|
||||||
|
"media-id": 52,
|
||||||
|
"scales": [
|
||||||
|
{
|
||||||
|
"id": 52,
|
||||||
|
"scale": 0,
|
||||||
|
"link": "https://<server>/photo/899184972463eb9b2ae3dc2580502826-0.png",
|
||||||
|
"width": 693,
|
||||||
|
"height": 835,
|
||||||
|
"size": 119523
|
||||||
|
},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
"thumb": "https://<server>/photo/899184972463eb9b2ae3dc2580502826-2.png"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
### GET api/friendica/profile/show
|
### GET api/friendica/profile/show
|
||||||
|
|
||||||
Returns the [Profile](help/API-Entities#Profile) data of the authenticated user.
|
Returns the [Profile](help/API-Entities#Profile) data of the authenticated user.
|
||||||
|
@ -715,6 +799,127 @@ General description of profile data in API returns:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### POST api/friendica/statuses/:id/dislike
|
||||||
|
|
||||||
|
Marks the given status as disliked by this user
|
||||||
|
|
||||||
|
#### Path Parameter
|
||||||
|
|
||||||
|
* `id`: the status ID that is being marked
|
||||||
|
|
||||||
|
#### Return values
|
||||||
|
|
||||||
|
A Mastodon [Status Entity](https://docs.joinmastodon.org/entities/Status/)
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
`https://<server_name>/api/friendica/statuses/341/dislike`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "341",
|
||||||
|
"created_at": "2023-02-23T01:50:00.000Z",
|
||||||
|
"in_reply_to_id": null,
|
||||||
|
"in_reply_to_status": null,
|
||||||
|
"in_reply_to_account_id": null,
|
||||||
|
"sensitive": false,
|
||||||
|
"spoiler_text": "",
|
||||||
|
"visibility": "public",
|
||||||
|
"language": "en",
|
||||||
|
...
|
||||||
|
"account": {
|
||||||
|
"id": "8",
|
||||||
|
"username": "testuser2",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"media_attachments": [],
|
||||||
|
"mentions": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"card": null,
|
||||||
|
"poll": null,
|
||||||
|
"friendica": {
|
||||||
|
"title": "",
|
||||||
|
"dislikes_count": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### GET api/friendica/statuses/:id/disliked_by
|
||||||
|
|
||||||
|
Returns the list of accounts that have disliked the status as known by the current server
|
||||||
|
|
||||||
|
#### Path Parameter
|
||||||
|
|
||||||
|
* `id`: the status ID that is being marked
|
||||||
|
|
||||||
|
#### Return values
|
||||||
|
|
||||||
|
A list of [Mastodon Account](https://docs.joinmastodon.org/entities/Account/) objects
|
||||||
|
in the body and next/previous link headers in the header
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
`https://<server_name>/api/friendica/statuses/341/disliked_by`
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"username": "testuser1",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### POST api/friendica/statuses/:id/undislike
|
||||||
|
|
||||||
|
Removes the dislike mark (if it exists) on this status for this user
|
||||||
|
|
||||||
|
#### Path Parameter
|
||||||
|
|
||||||
|
* `id`: the status ID that is being marked
|
||||||
|
|
||||||
|
#### Return values
|
||||||
|
|
||||||
|
A Mastodon [Status Entity](https://docs.joinmastodon.org/entities/Status/)
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
`https://<server_name>/api/friendica/statuses/341/dislike`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "341",
|
||||||
|
"created_at": "2023-02-23T01:50:00.000Z",
|
||||||
|
"in_reply_to_id": null,
|
||||||
|
"in_reply_to_status": null,
|
||||||
|
"in_reply_to_account_id": null,
|
||||||
|
"sensitive": false,
|
||||||
|
"spoiler_text": "",
|
||||||
|
"visibility": "public",
|
||||||
|
"language": "en",
|
||||||
|
...
|
||||||
|
"account": {
|
||||||
|
"id": "8",
|
||||||
|
"username": "testuser2",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"media_attachments": [],
|
||||||
|
"mentions": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"card": null,
|
||||||
|
"poll": null,
|
||||||
|
"friendica": {
|
||||||
|
"title": "",
|
||||||
|
"dislikes_count": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Deprecated endpoints
|
## Deprecated endpoints
|
||||||
|
|
||||||
- POST api/statuses/mediap
|
- POST api/statuses/mediap
|
||||||
|
|
|
@ -30,6 +30,100 @@ For supported apps please have a look at the [FAQ](help/FAQ#clients)
|
||||||
## Entities
|
## Entities
|
||||||
|
|
||||||
These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/entities/).
|
These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/entities/).
|
||||||
|
With some additional extensions listed below.
|
||||||
|
|
||||||
|
### Instance (Version 2) Entities
|
||||||
|
Extensions to the [Mastodon Instance::V2 Entities](https://docs.joinmastodon.org/entities/Instance/)
|
||||||
|
* `friendica`: Friendica specific properties of the V2 Instance including:
|
||||||
|
* `version`: The Friendica version string
|
||||||
|
* `codename`: The Friendica version code name
|
||||||
|
* `db_version`: The database schema version number
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "friendicadevtest1.myportal.social",
|
||||||
|
"title": "Friendica Social Network",
|
||||||
|
"version": "2.8.0 (compatible; Friendica 2023.03-dev)",
|
||||||
|
...
|
||||||
|
"friendica": {
|
||||||
|
"version": "2023.03-dev",
|
||||||
|
"codename": "Giant Rhubarb",
|
||||||
|
"db_version": 1516
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notification Entities
|
||||||
|
Extensions to the [Mastodon Notification Entities](https://docs.joinmastodon.org/entities/Notification/)
|
||||||
|
* `dismissed`: whether the object has been dismissed or not
|
||||||
|
|
||||||
|
### Status Entities
|
||||||
|
Extensions to the [Mastodon Status Entities](https://docs.joinmastodon.org/entities/Status/)
|
||||||
|
* `in_reply_to_status`: A fully populated Mastodon Status entity for the replied to status or null it is a post rather than a response
|
||||||
|
* `friendica`: Friendica specific properties of a status including:
|
||||||
|
* `title`: The Friendica title for a post, or empty if the status is a comment
|
||||||
|
* `delivery_data`: Information about the state of federating a message from the server
|
||||||
|
* `delivery_queue_count`: Total number of remote servers that the status needs to be federated to.
|
||||||
|
* `delivery_queue_done`: Total number of remote servers that have successfully been federated to so far.
|
||||||
|
* `delivery_queue_failed`: Total number of remote servers that have we failed to federate to so far.
|
||||||
|
* `dislikes_count`: The number of dislikes that a status has accumulated according to the server.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "358",
|
||||||
|
"created_at": "2023-02-23T02:45:46.000Z",
|
||||||
|
"in_reply_to_id": "356",
|
||||||
|
"in_reply_to_status": {
|
||||||
|
"id": "356",
|
||||||
|
"created_at": "2023-02-23T02:45:35.000Z",
|
||||||
|
"in_reply_to_id": null,
|
||||||
|
"in_reply_to_status": null,
|
||||||
|
"in_reply_to_account_id": null,
|
||||||
|
...
|
||||||
|
"content": "A post from testuser1",
|
||||||
|
...
|
||||||
|
"account": {
|
||||||
|
"id": "6",
|
||||||
|
"username": "testuser1",
|
||||||
|
"acct": "testuser1",
|
||||||
|
"display_name": "testuser1",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
...
|
||||||
|
"friendica": {
|
||||||
|
"title": "",
|
||||||
|
"dislikes_count": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"in_reply_to_account_id": "6",
|
||||||
|
...
|
||||||
|
"replies_count": 0,
|
||||||
|
"reblogs_count": 0,
|
||||||
|
"favourites_count": 0,
|
||||||
|
...
|
||||||
|
"content": "A reply from testuser2",
|
||||||
|
...
|
||||||
|
"account": {
|
||||||
|
"id": "8",
|
||||||
|
"username": "testuser2",
|
||||||
|
"acct": "testuser2",
|
||||||
|
"display_name": "testuser2",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
...
|
||||||
|
"friendica": {
|
||||||
|
"title": "",
|
||||||
|
"delivery_data": {
|
||||||
|
"delivery_queue_count": 10,
|
||||||
|
"delivery_queue_done": 3,
|
||||||
|
"delivery_queue_failed": 0
|
||||||
|
},
|
||||||
|
"dislikes_count": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Implemented endpoints
|
## Implemented endpoints
|
||||||
|
|
||||||
|
@ -73,8 +167,8 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
||||||
- `:id` is a follow request ID, not a regular account id
|
- `:id` is a follow request ID, not a regular account id
|
||||||
- Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object.
|
- Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object.
|
||||||
|
|
||||||
- [`GET /api/v1/followed_tags'](https://docs.joinmastodon.org/methods/followed_tags/)
|
- [`GET /api/v1/followed_tags`](https://docs.joinmastodon.org/methods/followed_tags/)
|
||||||
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance#fetch-instance)
|
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance/#v1)
|
||||||
- `GET /api/v1/instance/rules` Undocumented, returns Terms of Service
|
- `GET /api/v1/instance/rules` Undocumented, returns Terms of Service
|
||||||
- [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains)
|
- [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains)
|
||||||
- [`GET /api/v1/lists`](https://docs.joinmastodon.org/methods/timelines/lists/)
|
- [`GET /api/v1/lists`](https://docs.joinmastodon.org/methods/timelines/lists/)
|
||||||
|
@ -92,6 +186,10 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
||||||
- [`PUT /api/v1/media/:id`](https://docs.joinmastodon.org/methods/statuses/media/)
|
- [`PUT /api/v1/media/:id`](https://docs.joinmastodon.org/methods/statuses/media/)
|
||||||
- [`GET /api/v1/mutes`](https://docs.joinmastodon.org/methods/accounts/mutes/)
|
- [`GET /api/v1/mutes`](https://docs.joinmastodon.org/methods/accounts/mutes/)
|
||||||
- [`GET /api/v1/notifications`](https://docs.joinmastodon.org/methods/notifications/)
|
- [`GET /api/v1/notifications`](https://docs.joinmastodon.org/methods/notifications/)
|
||||||
|
- Additional field `include_all` to return read and unread statuses, defaults to `false`
|
||||||
|
- Additional field `summary` returns a count of all of the statuses that match the type filter
|
||||||
|
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
|
||||||
|
- Does not support the `type` field, which is the mirror image of the supported `exclude_types` field
|
||||||
- [`GET /api/v1/notifications/:id`](https://docs.joinmastodon.org/methods/notifications/)
|
- [`GET /api/v1/notifications/:id`](https://docs.joinmastodon.org/methods/notifications/)
|
||||||
- [`POST /api/v1/notifications/clear`](https://docs.joinmastodon.org/methods/notifications/)
|
- [`POST /api/v1/notifications/clear`](https://docs.joinmastodon.org/methods/notifications/)
|
||||||
- [`POST /api/v1/notifications/:id/dismiss`](https://docs.joinmastodon.org/methods/notifications/)
|
- [`POST /api/v1/notifications/:id/dismiss`](https://docs.joinmastodon.org/methods/notifications/)
|
||||||
|
@ -106,11 +204,22 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
||||||
- [`DELETE /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
|
- [`DELETE /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
|
||||||
- [`GET /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
|
- [`GET /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
|
||||||
- [`GET /api/v1/search`](https://docs.joinmastodon.org/methods/search/)
|
- [`GET /api/v1/search`](https://docs.joinmastodon.org/methods/search/)
|
||||||
|
- [`PUT /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#edit)
|
||||||
|
- Does not support `polls` argument as Friendica does not have polls
|
||||||
|
- Additional fields `friendica` for Friendica specific parameters:
|
||||||
|
- `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`.
|
||||||
- [`POST /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#create)
|
- [`POST /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#create)
|
||||||
|
- Does not support `polls` argument as Friendica does not have polls
|
||||||
- Additionally to the static values `public`, `unlisted` and `private`, the `visibility` parameter can contain a numeric value with a group id.
|
- Additionally to the static values `public`, `unlisted` and `private`, the `visibility` parameter can contain a numeric value with a group id.
|
||||||
|
- Additional field `quote_id` for the post that is being quote reshared
|
||||||
|
- Additional fields `friendica` for Friendica specific parameters:
|
||||||
|
- `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`.
|
||||||
- [`GET /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#get)
|
- [`GET /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#get)
|
||||||
- [`DELETE /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#delete)
|
- [`DELETE /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#delete)
|
||||||
- [`GET /api/v1/statuses/:id/context`](https://docs.joinmastodon.org/methods/statuses/#context)
|
- [`GET /api/v1/statuses/:id/context`](https://docs.joinmastodon.org/methods/statuses/#context)
|
||||||
|
- Additional support for paging using `min_id`, `max_id`, `since_id` parameters
|
||||||
|
- Additional support for previous/next Link Headers to support paging
|
||||||
|
- Additional flag `show_all` to allow including posts from blocked and ignored/muted users, defaults to `false`
|
||||||
- [`GET /api/v1/statuses/:id/reblogged_by`](https://docs.joinmastodon.org/methods/statuses/#reblogged_by)
|
- [`GET /api/v1/statuses/:id/reblogged_by`](https://docs.joinmastodon.org/methods/statuses/#reblogged_by)
|
||||||
- [`GET /api/v1/statuses/:id/favourited_by`](https://docs.joinmastodon.org/methods/statuses/#favourited_by)
|
- [`GET /api/v1/statuses/:id/favourited_by`](https://docs.joinmastodon.org/methods/statuses/#favourited_by)
|
||||||
- [`POST /api/v1/statuses/:id/favourite`](https://docs.joinmastodon.org/methods/statuses/#favourite)
|
- [`POST /api/v1/statuses/:id/favourite`](https://docs.joinmastodon.org/methods/statuses/#favourite)
|
||||||
|
@ -132,13 +241,24 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
||||||
- [`GET /api/v1/tags/:id/unfollow`](https://docs.joinmastodon.org/methods/tags/#unfollow)
|
- [`GET /api/v1/tags/:id/unfollow`](https://docs.joinmastodon.org/methods/tags/#unfollow)
|
||||||
- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/)
|
- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/)
|
||||||
- [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/)
|
- [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/)
|
||||||
|
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
|
||||||
|
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
|
||||||
- [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/)
|
- [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/)
|
||||||
|
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
|
||||||
|
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
|
||||||
- [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/)
|
- [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/)
|
||||||
|
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
|
||||||
|
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
|
||||||
- [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/)
|
- [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/)
|
||||||
|
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
|
||||||
|
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
|
||||||
|
- Does not support the `any[]`, `all[]`, or `none[]` query parameters
|
||||||
- [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/)
|
- [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/)
|
||||||
- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917)
|
- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917)
|
||||||
- [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses)
|
- [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses)
|
||||||
- [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags)
|
- [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags)
|
||||||
|
- Additional field `friendica_local` to return local trending tags instead of global tags, defaults to `false`
|
||||||
|
- [`GET /api/v2/instance`](https://docs.joinmastodon.org/methods/instance/#v2)
|
||||||
- [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/)
|
- [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,3 @@
|
||||||
<directory>.</directory>
|
<directory>.</directory>
|
||||||
</files>
|
</files>
|
||||||
</docblox>
|
</docblox>
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,8 @@ use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemURI;
|
use Friendica\Model\ItemURI;
|
||||||
use Friendica\Model\Photo;
|
|
||||||
use Friendica\Model\Post;
|
use Friendica\Model\Post;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Network\HTTPException;
|
||||||
use Friendica\Protocol\Activity;
|
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
|
||||||
function item_post(App $a) {
|
function item_post(App $a) {
|
||||||
|
@ -108,6 +106,7 @@ function item_edit(int $uid, array $request, bool $preview, string $return_path)
|
||||||
$post['edit'] = $post;
|
$post['edit'] = $post;
|
||||||
$post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']);
|
$post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']);
|
||||||
|
|
||||||
|
Post\Media::deleteByURIId($post['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]);
|
||||||
$post = item_process($post, $request, $preview, $return_path);
|
$post = item_process($post, $request, $preview, $return_path);
|
||||||
|
|
||||||
$fields = [
|
$fields = [
|
||||||
|
|
|
@ -4,12 +4,12 @@ Friendica mods files
|
||||||
## `bookmarklet-share2friendica`
|
## `bookmarklet-share2friendica`
|
||||||
|
|
||||||
Browser bookmarklet to share any page with your Friendica account.
|
Browser bookmarklet to share any page with your Friendica account.
|
||||||
Please see `bookmarklet-share2friendica/README.md` for detailed instruction.
|
Please see `bookmarklet-share2friendica/README.md` for detailed instruction.
|
||||||
|
|
||||||
## `fpostit`
|
## `fpostit`
|
||||||
|
|
||||||
Node-agnostic Friendica bookmarklet by Devlon Duthie.
|
Node-agnostic Friendica bookmarklet by Devlon Duthie.
|
||||||
Unmaintained and unsupported.
|
Unmaintained and unsupported.
|
||||||
|
|
||||||
## `home.css` and `home.html`
|
## `home.css` and `home.html`
|
||||||
|
|
||||||
|
@ -30,7 +30,11 @@ Please check software documentation to know how modify these examples to make th
|
||||||
## `sample-systemd.timer` and `sample-systemd.service`
|
## `sample-systemd.timer` and `sample-systemd.service`
|
||||||
|
|
||||||
Sample systemd unit files to start worker.php periodically.
|
Sample systemd unit files to start worker.php periodically.
|
||||||
|
|
||||||
Please place them in the correct location for your system, typically this is `/etc/systemd/system/friendicaworker.timer` and `/etc/systemd/system/friendicaworker.service`.
|
Please place them in the correct location for your system, typically this is `/etc/systemd/system/friendicaworker.timer` and `/etc/systemd/system/friendicaworker.service`.
|
||||||
Please report problems and improvements to `!helpers@forum.friendi.ca` and `@utzer@social.yl.ms` or open an issue in [the Github Friendica page](https://github.com/friendica/friendica/issues).
|
Please report problems and improvements to `!helpers@forum.friendi.ca` and `@utzer@social.yl.ms` or open an issue in [the Github Friendica page](https://github.com/friendica/friendica/issues).
|
||||||
This is for usage of systemd instead of cron to start the worker periodically, the solution is a work-in-progress and can surely be improved.
|
This is for usage of systemd instead of cron to start the worker periodically, the solution is a work-in-progress and can surely be improved.
|
||||||
|
|
||||||
|
## `phpstorm-code-style.xml`
|
||||||
|
|
||||||
|
PHP Storm Code Style settings, used for this codebase
|
||||||
|
|
34
mods/phpstorm-code-style.xml
Normal file
34
mods/phpstorm-code-style.xml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<code_scheme name="Default" version="173">
|
||||||
|
<Markdown>
|
||||||
|
<option name="WRAP_TEXT_IF_LONG" value="false" />
|
||||||
|
<option name="WRAP_TEXT_INSIDE_BLOCKQUOTES" value="false" />
|
||||||
|
</Markdown>
|
||||||
|
<PHPCodeStyleSettings>
|
||||||
|
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
|
||||||
|
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
|
||||||
|
<option name="ALIGN_PHPDOC_COMMENTS" value="true" />
|
||||||
|
<option name="ALIGN_ASSIGNMENTS" value="true" />
|
||||||
|
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||||
|
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
||||||
|
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||||
|
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||||
|
<option name="ELSE_IF_STYLE" value="SEPARATE" />
|
||||||
|
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
|
||||||
|
<option name="ALIGN_CLASS_CONSTANTS" value="true" />
|
||||||
|
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||||
|
</PHPCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="PHP">
|
||||||
|
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||||
|
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
|
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||||
|
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||||
|
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
24
ruleset.xml
24
ruleset.xml
|
@ -1,15 +1,15 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<ruleset name="Friendica">
|
<ruleset name="Friendica">
|
||||||
<description>Friendica Coding Standards: PSR2 with tabs instead of spaces</description>
|
<description>Friendica Coding Standards: PSR2 with tabs instead of spaces</description>
|
||||||
<arg name="tab-width" value="4"/>
|
<arg name="tab-width" value="4"/>
|
||||||
<rule ref="PSR2">
|
<rule ref="PSR2">
|
||||||
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
|
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||||
</rule>
|
</rule>
|
||||||
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
|
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
|
||||||
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="indent" value="4"/>
|
<property name="indent" value="4"/>
|
||||||
<property name="tabIndent" value="true"/>
|
<property name="tabIndent" value="true"/>
|
||||||
</properties>
|
</properties>
|
||||||
</rule>
|
</rule>
|
||||||
</ruleset>
|
</ruleset>
|
||||||
|
|
|
@ -73,7 +73,12 @@ class Avatar
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
try {
|
||||||
|
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
$img_str = $fetchResult->getBody();
|
$img_str = $fetchResult->getBody();
|
||||||
if (empty($img_str)) {
|
if (empty($img_str)) {
|
||||||
|
|
|
@ -437,7 +437,7 @@ class BBCode
|
||||||
* @param boolean $no_link_desc No link description
|
* @param boolean $no_link_desc No link description
|
||||||
* @return string with replaced body
|
* @return string with replaced body
|
||||||
*/
|
*/
|
||||||
public static function removeAttachment(string $body, bool $no_link_desc = false): string
|
public static function replaceAttachment(string $body, bool $no_link_desc = false): string
|
||||||
{
|
{
|
||||||
return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism",
|
return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism",
|
||||||
function ($match) use ($body, $no_link_desc) {
|
function ($match) use ($body, $no_link_desc) {
|
||||||
|
@ -454,6 +454,17 @@ class BBCode
|
||||||
}, $body);
|
}, $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove [attachment] BBCode
|
||||||
|
*
|
||||||
|
* @param string $body
|
||||||
|
* @return string with removed attachment
|
||||||
|
*/
|
||||||
|
public static function removeAttachment(string $body): string
|
||||||
|
{
|
||||||
|
return trim(preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a BBCode text into plaintext
|
* Converts a BBCode text into plaintext
|
||||||
*
|
*
|
||||||
|
@ -469,7 +480,7 @@ class BBCode
|
||||||
$text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text);
|
$text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text);
|
||||||
|
|
||||||
// Remove attachment
|
// Remove attachment
|
||||||
$text = self::removeAttachment($text);
|
$text = self::replaceAttachment($text);
|
||||||
|
|
||||||
$naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
|
$naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
|
||||||
|
|
||||||
|
@ -1583,9 +1594,9 @@ class BBCode
|
||||||
/// @todo Have a closer look at the different html modes
|
/// @todo Have a closer look at the different html modes
|
||||||
// Handle attached links or videos
|
// Handle attached links or videos
|
||||||
if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
|
if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
|
||||||
$text = self::removeAttachment($text);
|
$text = self::replaceAttachment($text);
|
||||||
} elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
|
} elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
|
||||||
$text = self::removeAttachment($text, true);
|
$text = self::replaceAttachment($text, true);
|
||||||
} else {
|
} else {
|
||||||
$text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid);
|
$text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ class StorageManager
|
||||||
|
|
||||||
return $data['storage_config'];
|
return $data['storage_config'];
|
||||||
} catch (InternalServerErrorException $exception) {
|
} catch (InternalServerErrorException $exception) {
|
||||||
throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception);
|
throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception->__toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ class StorageManager
|
||||||
$this->backendInstances[$name] = new Type\SystemResource();
|
$this->backendInstances[$name] = new Type\SystemResource();
|
||||||
break;
|
break;
|
||||||
case Type\ExternalResource::getName():
|
case Type\ExternalResource::getName():
|
||||||
$this->backendInstances[$name] = new Type\ExternalResource();
|
$this->backendInstances[$name] = new Type\ExternalResource($this->logger);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -223,7 +223,7 @@ class StorageManager
|
||||||
|
|
||||||
$this->backendInstances[$data['name'] ?? $name] = $data['storage'];
|
$this->backendInstances[$data['name'] ?? $name] = $data['storage'];
|
||||||
} catch (InternalServerErrorException $exception) {
|
} catch (InternalServerErrorException $exception) {
|
||||||
throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception);
|
throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception->__toString());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
namespace Friendica\Core\Storage\Type;
|
namespace Friendica\Core\Storage\Type;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Friendica\Core\Logger;
|
|
||||||
use Friendica\Core\Storage\Exception\ReferenceStorageException;
|
use Friendica\Core\Storage\Exception\ReferenceStorageException;
|
||||||
use Friendica\Core\Storage\Capability\ICanReadFromStorage;
|
use Friendica\Core\Storage\Capability\ICanReadFromStorage;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||||
use Friendica\Util\HTTPSignature;
|
use Friendica\Util\HTTPSignature;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External resource storage class
|
* External resource storage class
|
||||||
|
@ -39,6 +39,14 @@ class ExternalResource implements ICanReadFromStorage
|
||||||
{
|
{
|
||||||
const NAME = 'ExternalResource';
|
const NAME = 'ExternalResource';
|
||||||
|
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
@ -57,10 +65,11 @@ class ExternalResource implements ICanReadFromStorage
|
||||||
try {
|
try {
|
||||||
$fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
$fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
$this->logger->notice('URL is invalid', ['url' => $data->url, 'error' => $exception]);
|
||||||
throw new ReferenceStorageException(sprintf('External resource failed to get %s', $reference), $exception->getCode(), $exception);
|
throw new ReferenceStorageException(sprintf('External resource failed to get %s', $reference), $exception->getCode(), $exception);
|
||||||
}
|
}
|
||||||
if (!empty($fetchResult) && $fetchResult->isSuccess()) {
|
if (!empty($fetchResult) && $fetchResult->isSuccess()) {
|
||||||
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]);
|
$this->logger->debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]);
|
||||||
return $fetchResult->getBody();
|
return $fetchResult->getBody();
|
||||||
} else {
|
} else {
|
||||||
if (empty($fetchResult)) {
|
if (empty($fetchResult)) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Notification extends BaseFactory
|
||||||
if ($Notification->targetUriId) {
|
if ($Notification->targetUriId) {
|
||||||
try {
|
try {
|
||||||
$status = $this->mstdnStatusFactory->createFromUriId($Notification->targetUriId, $Notification->uid, $display_quotes);
|
$status = $this->mstdnStatusFactory->createFromUriId($Notification->targetUriId, $Notification->uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
$status = null;
|
$status = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -38,14 +38,14 @@ class Relationship extends BaseFactory
|
||||||
public function createFromContactId(int $contactId, int $uid): RelationshipEntity
|
public function createFromContactId(int $contactId, int $uid): RelationshipEntity
|
||||||
{
|
{
|
||||||
$cdata = Contact::getPublicAndUserContactID($contactId, $uid);
|
$cdata = Contact::getPublicAndUserContactID($contactId, $uid);
|
||||||
if (!empty($cdata)) {
|
$pcid = !empty($cdata['public']) ? $cdata['public'] : $contactId;
|
||||||
$cid = $cdata['user'];
|
$cid = !empty($cdata['user']) ? $cdata['user'] : $contactId;
|
||||||
$pcid = $cdata['public'];
|
|
||||||
} else {
|
|
||||||
$pcid = $cid = $contactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RelationshipEntity($pcid, Contact::getById($cid),
|
return new RelationshipEntity(
|
||||||
Contact\User::isBlocked($cid, $uid), Contact\User::isIgnored($cid, $uid));
|
$pcid,
|
||||||
|
Contact::getById($cid),
|
||||||
|
Contact\User::isBlocked($cid, $uid),
|
||||||
|
Contact\User::isIgnored($cid, $uid)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ use Friendica\Model\Post;
|
||||||
use Friendica\Model\Tag as TagModel;
|
use Friendica\Model\Tag as TagModel;
|
||||||
use Friendica\Model\Verb;
|
use Friendica\Model\Verb;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Network\HTTPException;
|
||||||
|
use Friendica\Object\Api\Mastodon\Status\FriendicaDeliveryData;
|
||||||
|
use Friendica\Object\Api\Mastodon\Status\FriendicaExtension;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Protocol\ActivityPub;
|
use Friendica\Protocol\ActivityPub;
|
||||||
use ImagickException;
|
use ImagickException;
|
||||||
|
@ -97,7 +99,8 @@ class Status extends BaseFactory
|
||||||
public function createFromUriId(int $uriId, int $uid = 0, bool $display_quote = false, bool $reblog = true, bool $in_reply_status = true): \Friendica\Object\Api\Mastodon\Status
|
public function createFromUriId(int $uriId, int $uid = 0, bool $display_quote = false, bool $reblog = true, bool $in_reply_status = true): \Friendica\Object\Api\Mastodon\Status
|
||||||
{
|
{
|
||||||
$fields = ['uri-id', 'uid', 'author-id', 'causer-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
$fields = ['uri-id', 'uid', 'author-id', 'causer-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||||
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id'];
|
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id',
|
||||||
|
'delivery_queue_count', 'delivery_queue_done','delivery_queue_failed'];
|
||||||
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
||||||
if (!$item) {
|
if (!$item) {
|
||||||
$mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]);
|
$mail = DBA::selectFirst('mail', ['id'], ['uri-id' => $uriId, 'uid' => $uid]);
|
||||||
|
@ -266,8 +269,8 @@ class Status extends BaseFactory
|
||||||
if ($is_reshare) {
|
if ($is_reshare) {
|
||||||
try {
|
try {
|
||||||
$reshare = $this->createFromUriId($uriId, $uid, $display_quote, false, false)->toArray();
|
$reshare = $this->createFromUriId($uriId, $uid, $display_quote, false, false)->toArray();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
$reshare = [];
|
$reshare = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -277,15 +280,18 @@ class Status extends BaseFactory
|
||||||
if ($in_reply_status && ($item['gravity'] == Item::GRAVITY_COMMENT)) {
|
if ($in_reply_status && ($item['gravity'] == Item::GRAVITY_COMMENT)) {
|
||||||
try {
|
try {
|
||||||
$in_reply = $this->createFromUriId($item['thr-parent-id'], $uid, $display_quote, false, false)->toArray();
|
$in_reply = $this->createFromUriId($item['thr-parent-id'], $uid, $display_quote, false, false)->toArray();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
$in_reply = [];
|
$in_reply = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$in_reply = [];
|
$in_reply = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $quote, $poll);
|
$delivery_data = new FriendicaDeliveryData($item['delivery_queue_count'], $item['delivery_queue_done'], $item['delivery_queue_failed']);
|
||||||
|
$friendica = new FriendicaExtension($item['title'], $counts->dislikes, $delivery_data);
|
||||||
|
|
||||||
|
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica, $quote, $poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -309,8 +315,8 @@ class Status extends BaseFactory
|
||||||
if (!empty($quote_id)) {
|
if (!empty($quote_id)) {
|
||||||
try {
|
try {
|
||||||
$quote = $this->createFromUriId($quote_id, $uid, false, false, false)->toArray();
|
$quote = $this->createFromUriId($quote_id, $uid, false, false, false)->toArray();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
$quote = [];
|
$quote = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,7 +355,8 @@ class Status extends BaseFactory
|
||||||
$attachments = [];
|
$attachments = [];
|
||||||
$in_reply = [];
|
$in_reply = [];
|
||||||
$reshare = [];
|
$reshare = [];
|
||||||
|
$friendica = new FriendicaExtension('', 0, new FriendicaDeliveryData(0, 0, 0));
|
||||||
|
|
||||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare);
|
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,17 +189,22 @@ class APContact
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
$local_owner = [];
|
$local_owner = [];
|
||||||
|
|
||||||
$curlResult = HTTPSignature::fetchRaw($url);
|
try {
|
||||||
$failed = empty($curlResult) || empty($curlResult->getBody()) ||
|
$curlResult = HTTPSignature::fetchRaw($url);
|
||||||
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
|
$failed = empty($curlResult) || empty($curlResult->getBody()) ||
|
||||||
|
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
|
||||||
|
|
||||||
|
if (!$failed) {
|
||||||
|
$data = json_decode($curlResult->getBody(), true);
|
||||||
|
$failed = empty($data) || !is_array($data);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$failed) {
|
if (!$failed && ($curlResult->getReturnCode() == 410)) {
|
||||||
$data = json_decode($curlResult->getBody(), true);
|
$data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
|
||||||
$failed = empty($data) || !is_array($data);
|
}
|
||||||
}
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
|
||||||
if (!$failed && ($curlResult->getReturnCode() == 410)) {
|
$failed = true;
|
||||||
$data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($failed) {
|
if ($failed) {
|
||||||
|
|
|
@ -2216,16 +2216,21 @@ class Contact
|
||||||
if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) {
|
if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) {
|
||||||
$update_fields = ['avatar' => $avatar];
|
$update_fields = ['avatar' => $avatar];
|
||||||
if (!Network::isLocalLink($avatar)) {
|
if (!Network::isLocalLink($avatar)) {
|
||||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
try {
|
||||||
|
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||||
|
|
||||||
$img_str = $fetchResult->getBody();
|
$img_str = $fetchResult->getBody();
|
||||||
if (!empty($img_str)) {
|
if (!empty($img_str)) {
|
||||||
$image = new Image($img_str, Images::getMimeTypeByData($img_str));
|
$image = new Image($img_str, Images::getMimeTypeByData($img_str));
|
||||||
if ($image->isValid()) {
|
if ($image->isValid()) {
|
||||||
$update_fields['blurhash'] = $image->getBlurHash();
|
$update_fields['blurhash'] = $image->getBlurHash();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching avatar', ['avatar' => $avatar, 'exception' => $exception]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} elseif (!empty($contact['blurhash'])) {
|
} elseif (!empty($contact['blurhash'])) {
|
||||||
$update_fields['blurhash'] = null;
|
$update_fields['blurhash'] = null;
|
||||||
|
|
|
@ -210,8 +210,6 @@ class Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']);
|
|
||||||
|
|
||||||
$content_fields = ['raw-body' => trim($fields['raw-body'] ?? $fields['body'])];
|
$content_fields = ['raw-body' => trim($fields['raw-body'] ?? $fields['body'])];
|
||||||
|
|
||||||
// Remove all media attachments from the body and store them in the post-media table
|
// Remove all media attachments from the body and store them in the post-media table
|
||||||
|
@ -220,6 +218,10 @@ class Item
|
||||||
$content_fields['raw-body'] = self::setHashtags($content_fields['raw-body']);
|
$content_fields['raw-body'] = self::setHashtags($content_fields['raw-body']);
|
||||||
|
|
||||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $content_fields['raw-body'], $fields['body'], $item['author-network']);
|
Post\Media::insertFromRelevantUrl($item['uri-id'], $content_fields['raw-body'], $fields['body'], $item['author-network']);
|
||||||
|
|
||||||
|
Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']);
|
||||||
|
$content_fields['raw-body'] = BBCode::removeAttachment($content_fields['raw-body']);
|
||||||
|
|
||||||
Post\Content::update($item['uri-id'], $content_fields);
|
Post\Content::update($item['uri-id'], $content_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,8 +1145,6 @@ class Item
|
||||||
$item['body'] = BBCode::removeSharedData($item['body']);
|
$item['body'] = BBCode::removeSharedData($item['body']);
|
||||||
}
|
}
|
||||||
|
|
||||||
Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']);
|
|
||||||
|
|
||||||
// Remove all media attachments from the body and store them in the post-media table
|
// Remove all media attachments from the body and store them in the post-media table
|
||||||
$item['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $item['raw-body']);
|
$item['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $item['raw-body']);
|
||||||
$item['raw-body'] = self::setHashtags($item['raw-body']);
|
$item['raw-body'] = self::setHashtags($item['raw-body']);
|
||||||
|
@ -1152,6 +1152,10 @@ class Item
|
||||||
$author = Contact::getById($item['author-id'], ['network']);
|
$author = Contact::getById($item['author-id'], ['network']);
|
||||||
Post\Media::insertFromRelevantUrl($item['uri-id'], $item['raw-body'], $item['body'], $author['network'] ?? '');
|
Post\Media::insertFromRelevantUrl($item['uri-id'], $item['raw-body'], $item['body'], $author['network'] ?? '');
|
||||||
|
|
||||||
|
Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']);
|
||||||
|
$item['body'] = BBCode::removeAttachment($item['body']);
|
||||||
|
$item['raw-body'] = BBCode::removeAttachment($item['raw-body']);
|
||||||
|
|
||||||
// Check for hashtags in the body and repair or add hashtag links
|
// Check for hashtags in the body and repair or add hashtag links
|
||||||
$item['body'] = self::setHashtags($item['body']);
|
$item['body'] = self::setHashtags($item['body']);
|
||||||
|
|
||||||
|
@ -3003,8 +3007,9 @@ class Item
|
||||||
|
|
||||||
$fields = ['uri-id', 'uri', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink', 'network', 'has-media', 'quote-uri-id', 'post-type'];
|
$fields = ['uri-id', 'uri', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink', 'network', 'has-media', 'quote-uri-id', 'post-type'];
|
||||||
|
|
||||||
$shared_uri_id = 0;
|
$shared_uri_id = 0;
|
||||||
$shared_links = [];
|
$shared_links = [];
|
||||||
|
$quote_shared_links = [];
|
||||||
|
|
||||||
$shared = DI::contentItem()->getSharedPost($item, $fields);
|
$shared = DI::contentItem()->getSharedPost($item, $fields);
|
||||||
if (!empty($shared['post'])) {
|
if (!empty($shared['post'])) {
|
||||||
|
@ -3023,7 +3028,14 @@ class Item
|
||||||
$shared_links[] = strtolower($media[0]['url']);
|
$shared_links[] = strtolower($media[0]['url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$quote_uri_id = $shared_item['uri-id'] ?? 0;
|
if (!empty($shared_item['uri-id'])) {
|
||||||
|
$data = BBCode::getAttachmentData($shared_item['body']);
|
||||||
|
if (!empty($data['url'])) {
|
||||||
|
$quote_shared_links[] = $data['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$quote_uri_id = $shared_item['uri-id'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3098,7 +3110,7 @@ class Item
|
||||||
|
|
||||||
if (!empty($shared_attachments)) {
|
if (!empty($shared_attachments)) {
|
||||||
$s = self::addVisualAttachments($shared_attachments, $shared_item, $s, true);
|
$s = self::addVisualAttachments($shared_attachments, $shared_item, $s, true);
|
||||||
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, []);
|
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, $quote_shared_links);
|
||||||
$s = self::addNonVisualAttachments($shared_attachments, $item, $s, true);
|
$s = self::addNonVisualAttachments($shared_attachments, $item, $s, true);
|
||||||
$body = BBCode::removeSharedData($body);
|
$body = BBCode::removeSharedData($body);
|
||||||
}
|
}
|
||||||
|
@ -3418,7 +3430,7 @@ class Item
|
||||||
DI::profiler()->stopRecording();
|
DI::profiler()->stopRecording();
|
||||||
|
|
||||||
if (isset($data['url']) && !in_array(strtolower($data['url']), $ignore_links)) {
|
if (isset($data['url']) && !in_array(strtolower($data['url']), $ignore_links)) {
|
||||||
if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview'])) {
|
if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview']) || (!empty($data['title']) && !Strings::compareLink($data['title'], $data['url']))) {
|
||||||
$parts = parse_url($data['url']);
|
$parts = parse_url($data['url']);
|
||||||
if (!empty($parts['scheme']) && !empty($parts['host'])) {
|
if (!empty($parts['scheme']) && !empty($parts['host'])) {
|
||||||
if (empty($data['provider_name'])) {
|
if (empty($data['provider_name'])) {
|
||||||
|
|
|
@ -125,8 +125,13 @@ class Link
|
||||||
{
|
{
|
||||||
$timeout = DI::config()->get('system', 'xrd_timeout');
|
$timeout = DI::config()->get('system', 'xrd_timeout');
|
||||||
|
|
||||||
$curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]);
|
try {
|
||||||
if (empty($curlResult) || !$curlResult->isSuccess()) {
|
$curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]);
|
||||||
|
if (empty($curlResult) || !$curlResult->isSuccess()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$fields = ['mimetype' => $curlResult->getHeader('Content-Type')[0]];
|
$fields = ['mimetype' => $curlResult->getHeader('Content-Type')[0]];
|
||||||
|
|
|
@ -68,18 +68,18 @@ class Media
|
||||||
*
|
*
|
||||||
* @param array $media
|
* @param array $media
|
||||||
* @param bool $force
|
* @param bool $force
|
||||||
* @return void
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function insert(array $media, bool $force = false)
|
public static function insert(array $media, bool $force = false): bool
|
||||||
{
|
{
|
||||||
if (empty($media['url']) || empty($media['uri-id']) || !isset($media['type'])) {
|
if (empty($media['url']) || empty($media['uri-id']) || !isset($media['type'])) {
|
||||||
Logger::warning('Incomplete media data', ['media' => $media]);
|
Logger::warning('Incomplete media data', ['media' => $media]);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBA::exists('post-media', ['uri-id' => $media['uri-id'], 'preview' => $media['url']])) {
|
if (DBA::exists('post-media', ['uri-id' => $media['uri-id'], 'preview' => $media['url']])) {
|
||||||
Logger::info('Media already exists as preview', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
Logger::info('Media already exists as preview', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "document" has got the lowest priority. So when the same file is both attached as document
|
// "document" has got the lowest priority. So when the same file is both attached as document
|
||||||
|
@ -87,12 +87,12 @@ class Media
|
||||||
$found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
$found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||||
if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) {
|
if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) {
|
||||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ItemURI::exists($media['uri-id'])) {
|
if (!ItemURI::exists($media['uri-id'])) {
|
||||||
Logger::info('Media referenced URI ID not found', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
Logger::info('Media referenced URI ID not found', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$media = self::unsetEmptyFields($media);
|
$media = self::unsetEmptyFields($media);
|
||||||
|
@ -114,6 +114,7 @@ class Media
|
||||||
} else {
|
} else {
|
||||||
Logger::info('Nothing to update', ['media' => $media]);
|
Logger::info('Nothing to update', ['media' => $media]);
|
||||||
}
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -573,9 +574,14 @@ class Media
|
||||||
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches)) {
|
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches)) {
|
||||||
foreach ($matches[1] as $url) {
|
foreach ($matches[1] as $url) {
|
||||||
Logger::info('Got page url (link without description)', ['uri-id' => $uriid, 'url' => $url]);
|
Logger::info('Got page url (link without description)', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
$result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
||||||
if ($network == Protocol::DFRN) {
|
if ($result && ($network == Protocol::DFRN)) {
|
||||||
self::revertHTMLType($uriid, $url, $fullbody);
|
self::revertHTMLType($uriid, $url, $fullbody);
|
||||||
|
Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
|
} elseif ($result) {
|
||||||
|
Logger::debug('Media had been added', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
|
} else {
|
||||||
|
Logger::debug('Media had not been added', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,9 +590,14 @@ class Media
|
||||||
if (preg_match_all("/\[url\=(https?:.*?)\].*?\[\/url\]/ism", $body, $matches)) {
|
if (preg_match_all("/\[url\=(https?:.*?)\].*?\[\/url\]/ism", $body, $matches)) {
|
||||||
foreach ($matches[1] as $url) {
|
foreach ($matches[1] as $url) {
|
||||||
Logger::info('Got page url (link with description)', ['uri-id' => $uriid, 'url' => $url]);
|
Logger::info('Got page url (link with description)', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
$result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
||||||
if ($network == Protocol::DFRN) {
|
if ($result && ($network == Protocol::DFRN)) {
|
||||||
self::revertHTMLType($uriid, $url, $fullbody);
|
self::revertHTMLType($uriid, $url, $fullbody);
|
||||||
|
Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
|
} elseif ($result) {
|
||||||
|
Logger::debug('Media has been added', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
|
} else {
|
||||||
|
Logger::debug('Media has not been added', ['uri-id' => $uriid, 'url' => $url]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,6 +716,25 @@ class Media
|
||||||
return DBA::exists('post-media', $condition);
|
return DBA::exists('post-media', $condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete media by uri-id and media type
|
||||||
|
*
|
||||||
|
* @param int $uri_id URI id
|
||||||
|
* @param array $types Media types
|
||||||
|
* @return bool Whether media attachment exists
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function deleteByURIId(int $uri_id, array $types = []): bool
|
||||||
|
{
|
||||||
|
$condition = ['uri-id' => $uri_id];
|
||||||
|
|
||||||
|
if (!empty($types)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ['type' => $types]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBA::delete('post-media', $condition);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split the attachment media in the three segments "visual", "link" and "additional"
|
* Split the attachment media in the three segments "visual", "link" and "additional"
|
||||||
*
|
*
|
||||||
|
@ -830,7 +860,7 @@ class Media
|
||||||
}
|
}
|
||||||
$original_body = $body;
|
$original_body = $body;
|
||||||
|
|
||||||
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
|
$body = BBCode::removeAttachment($body);
|
||||||
|
|
||||||
foreach (self::getByURIId($uriid, $types) as $media) {
|
foreach (self::getByURIId($uriid, $types) as $media) {
|
||||||
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {
|
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {
|
||||||
|
|
|
@ -120,8 +120,8 @@ class Statuses extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -77,8 +77,8 @@ class Bookmarks extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -79,8 +79,8 @@ class Favourited extends BaseApi
|
||||||
self::setBoundaries($item['thr-parent-id']);
|
self::setBoundaries($item['thr-parent-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -117,7 +117,7 @@ class Accounts extends BaseApi
|
||||||
self::setBoundaries($member['contact-id']);
|
self::setBoundaries($member['contact-id']);
|
||||||
try {
|
try {
|
||||||
$accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid);
|
$accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($members);
|
DBA::close($members);
|
||||||
|
|
|
@ -183,8 +183,8 @@ class Search extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -45,10 +45,11 @@ class Context extends BaseApi
|
||||||
}
|
}
|
||||||
|
|
||||||
$request = $this->getRequest([
|
$request = $this->getRequest([
|
||||||
'max_id' => 0, // Return results older than this id
|
'max_id' => 0, // Return results older than this id
|
||||||
'since_id' => 0, // Return results newer than this id
|
'since_id' => 0, // Return results newer than this id
|
||||||
'min_id' => 0, // Return results immediately newer than this id
|
'min_id' => 0, // Return results immediately newer than this id
|
||||||
'limit' => 40, // Maximum number of results to return. Defaults to 40.
|
'limit' => 40, // Maximum number of results to return. Defaults to 40.
|
||||||
|
'show_all' => false, // shows posts for all users including blocked and ignored users
|
||||||
], $request);
|
], $request);
|
||||||
|
|
||||||
$id = $this->parameters['id'];
|
$id = $this->parameters['id'];
|
||||||
|
@ -73,6 +74,13 @@ class Context extends BaseApi
|
||||||
$condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]);
|
$condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]);
|
||||||
$params['order'] = ['uri-id'];
|
$params['order'] = ['uri-id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($uid) && !$request['show_all']) {
|
||||||
|
$condition = DBA::mergeConditions(
|
||||||
|
$condition,
|
||||||
|
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`))", $uid]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$posts = Post::selectPosts(['uri-id', 'thr-parent-id'], $condition, $params);
|
$posts = Post::selectPosts(['uri-id', 'thr-parent-id'], $condition, $params);
|
||||||
while ($post = Post::fetch($posts)) {
|
while ($post = Post::fetch($posts)) {
|
||||||
|
|
|
@ -104,8 +104,8 @@ class ListTimeline extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -99,8 +99,8 @@ class PublicTimeline extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -120,8 +120,8 @@ class Tag extends BaseApi
|
||||||
self::setBoundaries($item['uri-id']);
|
self::setBoundaries($item['uri-id']);
|
||||||
try {
|
try {
|
||||||
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($items);
|
DBA::close($items);
|
||||||
|
|
|
@ -57,8 +57,8 @@ class Statuses extends BaseApi
|
||||||
while ($status = Post::fetch($statuses)) {
|
while ($status = Post::fetch($statuses)) {
|
||||||
try {
|
try {
|
||||||
$trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid, $display_quotes);
|
$trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid, $display_quotes);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'error' => $th]);
|
Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'exception' => $exception]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($statuses);
|
DBA::close($statuses);
|
||||||
|
|
|
@ -115,6 +115,8 @@ class Edit extends BaseModule
|
||||||
$lockstate = 'unlock';
|
$lockstate = 'unlock';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$item['body'] = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
|
||||||
|
|
||||||
$jotplugins = '';
|
$jotplugins = '';
|
||||||
|
|
||||||
Hook::callAll('jot_tool', $jotplugins);
|
Hook::callAll('jot_tool', $jotplugins);
|
||||||
|
|
|
@ -83,13 +83,18 @@ class Proxy extends BaseModule
|
||||||
$request['url'] = str_replace(' ', '+', $request['url']);
|
$request['url'] = str_replace(' ', '+', $request['url']);
|
||||||
|
|
||||||
// Fetch the content with the local user
|
// Fetch the content with the local user
|
||||||
$fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]);
|
try {
|
||||||
$img_str = $fetchResult->getBody();
|
$fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]);
|
||||||
|
$img_str = $fetchResult->getBody();
|
||||||
|
|
||||||
if (!$fetchResult->isSuccess() || empty($img_str)) {
|
if (!$fetchResult->isSuccess() || empty($img_str)) {
|
||||||
Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
|
Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
|
||||||
|
self::responseError();
|
||||||
|
// stop.
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching image', ['image' => $request['url'], 'exception' => $exception]);
|
||||||
self::responseError();
|
self::responseError();
|
||||||
// stop.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]);
|
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]);
|
||||||
|
|
|
@ -84,14 +84,14 @@ class Instance extends BaseDataTransferObject
|
||||||
{
|
{
|
||||||
$register_policy = intval($config->get('config', 'register_policy'));
|
$register_policy = intval($config->get('config', 'register_policy'));
|
||||||
|
|
||||||
$this->uri = $baseUrl;
|
$this->uri = $baseUrl->getHost();
|
||||||
$this->title = $config->get('config', 'sitename');
|
$this->title = $config->get('config', 'sitename');
|
||||||
$this->short_description = $this->description = $config->get('config', 'info');
|
$this->short_description = $this->description = $config->get('config', 'info');
|
||||||
$this->email = implode(',', User::getAdminEmailList());
|
$this->email = implode(',', User::getAdminEmailList());
|
||||||
$this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')';
|
$this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')';
|
||||||
$this->urls = null; // Not supported
|
$this->urls = null; // Not supported
|
||||||
$this->stats = new Stats($config, $database);
|
$this->stats = new Stats($config, $database);
|
||||||
$this->thumbnail = $baseUrl . 'images/friendica-banner.jpg';
|
$this->thumbnail = $baseUrl . '/images/friendica-banner.jpg';
|
||||||
$this->languages = [$config->get('system', 'language')];
|
$this->languages = [$config->get('system', 'language')];
|
||||||
$this->max_toot_chars = (int)$config->get('config', 'api_import_size', $config->get('config', 'max_import_size'));
|
$this->max_toot_chars = (int)$config->get('config', 'api_import_size', $config->get('config', 'max_import_size'));
|
||||||
$this->registrations = ($register_policy != Register::CLOSED);
|
$this->registrations = ($register_policy != Register::CLOSED);
|
||||||
|
|
|
@ -39,9 +39,9 @@ class Contact extends BaseDataTransferObject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $email
|
* @param string $email
|
||||||
* @param Account $account
|
* @param Account|null $account
|
||||||
*/
|
*/
|
||||||
public function __construct(string $email, Account $account)
|
public function __construct(string $email, ?Account $account)
|
||||||
{
|
{
|
||||||
$this->email = $email;
|
$this->email = $email;
|
||||||
$this->account = $account;
|
$this->account = $account;
|
||||||
|
|
|
@ -31,13 +31,13 @@ use Friendica\BaseDataTransferObject;
|
||||||
class UserStats extends BaseDataTransferObject
|
class UserStats extends BaseDataTransferObject
|
||||||
{
|
{
|
||||||
/** @var int */
|
/** @var int */
|
||||||
protected $active_monthly = 0;
|
protected $active_month = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $active_monthly
|
* @param int $active_month
|
||||||
*/
|
*/
|
||||||
public function __construct($active_monthly)
|
public function __construct(int $active_month)
|
||||||
{
|
{
|
||||||
$this->active_monthly = $active_monthly;
|
$this->active_month = $active_month;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ class Status extends BaseDataTransferObject
|
||||||
* @param array $item
|
* @param array $item
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
*/
|
*/
|
||||||
public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card, array $attachments, array $in_reply, array $reblog, array $quote = null, array $poll = null)
|
public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card, array $attachments, array $in_reply, array $reblog, FriendicaExtension $friendica, array $quote = null, array $poll = null)
|
||||||
{
|
{
|
||||||
$this->id = (string)$item['uri-id'];
|
$this->id = (string)$item['uri-id'];
|
||||||
$this->created_at = DateTimeFormat::utc($item['created'], DateTimeFormat::JSON);
|
$this->created_at = DateTimeFormat::utc($item['created'], DateTimeFormat::JSON);
|
||||||
|
@ -151,7 +151,7 @@ class Status extends BaseDataTransferObject
|
||||||
$this->emojis = [];
|
$this->emojis = [];
|
||||||
$this->card = $card->toArray() ?: null;
|
$this->card = $card->toArray() ?: null;
|
||||||
$this->poll = $poll;
|
$this->poll = $poll;
|
||||||
$this->friendica = new FriendicaExtension($item['title'], $counts->dislikes);
|
$this->friendica = $friendica;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
55
src/Object/Api/Mastodon/Status/FriendicaDeliveryData.php
Normal file
55
src/Object/Api/Mastodon/Status/FriendicaDeliveryData.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (C) 2010-2023, 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\Mastodon\Status;
|
||||||
|
|
||||||
|
use Friendica\BaseDataTransferObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FriendicaDeliveryData
|
||||||
|
*
|
||||||
|
* Additional fields on Mastodon Statuses for storing Friendica delivery data
|
||||||
|
*
|
||||||
|
* @see https://docs.joinmastodon.org/entities/status
|
||||||
|
*/
|
||||||
|
class FriendicaDeliveryData extends BaseDataTransferObject
|
||||||
|
{
|
||||||
|
/** @var int|null */
|
||||||
|
protected $delivery_queue_count;
|
||||||
|
|
||||||
|
/** @var int|null */
|
||||||
|
protected $delivery_queue_done;
|
||||||
|
|
||||||
|
/** @var int|null */
|
||||||
|
protected $delivery_queue_failed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FriendicaDeliveryData object
|
||||||
|
*
|
||||||
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
|
*/
|
||||||
|
public function __construct(?int $delivery_queue_count, ?int $delivery_queue_done, ?int $delivery_queue_failed)
|
||||||
|
{
|
||||||
|
$this->delivery_queue_count = $delivery_queue_count;
|
||||||
|
$this->delivery_queue_done = $delivery_queue_done;
|
||||||
|
$this->delivery_queue_failed = $delivery_queue_failed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,8 @@ class FriendicaExtension extends BaseDataTransferObject
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $title;
|
protected $title;
|
||||||
|
|
||||||
|
/** @var FriendicaDeliveryData */
|
||||||
|
protected $delivery_data;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
protected $dislikes_count;
|
protected $dislikes_count;
|
||||||
|
|
||||||
|
@ -42,11 +44,13 @@ class FriendicaExtension extends BaseDataTransferObject
|
||||||
* Creates a status count object
|
* Creates a status count object
|
||||||
*
|
*
|
||||||
* @param string $title
|
* @param string $title
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @param int $dislikes_count
|
||||||
|
* @param FriendicaDeliveryData $delivery_data
|
||||||
*/
|
*/
|
||||||
public function __construct(string $title, int $dislikes_count)
|
public function __construct(string $title, int $dislikes_count, FriendicaDeliveryData $delivery_data)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
|
$this->delivery_data = $delivery_data;
|
||||||
$this->dislikes_count = $dislikes_count;
|
$this->dislikes_count = $dislikes_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,7 +718,7 @@ class Image
|
||||||
if ($image->isImagick()) {
|
if ($image->isImagick()) {
|
||||||
try {
|
try {
|
||||||
$colors = $image->image->getImagePixelColor($x, $y)->getColor();
|
$colors = $image->image->getImagePixelColor($x, $y)->getColor();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Exception $exception) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$row[] = [$colors['r'], $colors['g'], $colors['b']];
|
$row[] = [$colors['r'], $colors['g'], $colors['b']];
|
||||||
|
|
|
@ -242,6 +242,7 @@ class Processor
|
||||||
$item['changed'] = DateTimeFormat::utcNow();
|
$item['changed'] = DateTimeFormat::utcNow();
|
||||||
$item['edited'] = DateTimeFormat::utc($activity['updated']);
|
$item['edited'] = DateTimeFormat::utc($activity['updated']);
|
||||||
|
|
||||||
|
Post\Media::deleteByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]);
|
||||||
$item = self::processContent($activity, $item);
|
$item = self::processContent($activity, $item);
|
||||||
if (empty($item)) {
|
if (empty($item)) {
|
||||||
Queue::remove($activity);
|
Queue::remove($activity);
|
||||||
|
@ -570,7 +571,12 @@ class Processor
|
||||||
*/
|
*/
|
||||||
public static function isActivityGone(string $url): bool
|
public static function isActivityGone(string $url): bool
|
||||||
{
|
{
|
||||||
$curlResult = HTTPSignature::fetchRaw($url, 0);
|
try {
|
||||||
|
$curlResult = HTTPSignature::fetchRaw($url, 0);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (Network::isUrlBlocked($url)) {
|
if (Network::isUrlBlocked($url)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1675,7 +1675,7 @@ class Transmitter
|
||||||
if ($type == 'Page') {
|
if ($type == 'Page') {
|
||||||
// When we transmit "Page" posts we have to remove the attachment.
|
// When we transmit "Page" posts we have to remove the attachment.
|
||||||
// The attachment contains the link that we already transmit in the "url" field.
|
// The attachment contains the link that we already transmit in the "url" field.
|
||||||
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
|
$body = BBCode::removeAttachment($body);
|
||||||
}
|
}
|
||||||
|
|
||||||
$body = BBCode::setMentionsToNicknames($body);
|
$body = BBCode::setMentionsToNicknames($body);
|
||||||
|
@ -1707,7 +1707,7 @@ class Transmitter
|
||||||
$richbody = DI::contentItem()->addSharedPost($item, $richbody);
|
$richbody = DI::contentItem()->addSharedPost($item, $richbody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$richbody = BBCode::removeAttachment($richbody);
|
$richbody = BBCode::replaceAttachment($richbody);
|
||||||
|
|
||||||
$data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL);
|
$data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,7 +422,12 @@ class HTTPSignature
|
||||||
*/
|
*/
|
||||||
public static function fetch(string $request, int $uid): array
|
public static function fetch(string $request, int $uid): array
|
||||||
{
|
{
|
||||||
$curlResult = self::fetchRaw($request, $uid);
|
try {
|
||||||
|
$curlResult = self::fetchRaw($request, $uid);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Logger::notice('Error fetching url', ['url' => $request, 'exception' => $exception]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($curlResult)) {
|
if (empty($curlResult)) {
|
||||||
return [];
|
return [];
|
||||||
|
|
Loading…
Reference in a new issue