-- ------------------------------------------
-- Friendica 2022.05-rc (Siberian Iris)
--- DB_UPDATE_VERSION 1467
+-- DB_UPDATE_VERSION 1468
-- ------------------------------------------
UNIQUE INDEX `client_id` (`client_id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth application';
+--
+-- TABLE application-marker
+--
+CREATE TABLE IF NOT EXISTS `application-marker` (
+ `application-id` int unsigned NOT NULL COMMENT '',
+ `uid` mediumint unsigned NOT NULL COMMENT 'Owner User id',
+ `timeline` varchar(64) NOT NULL COMMENT 'Marker (home, notifications)',
+ `last_read_id` varchar(255) COMMENT 'Marker id for the timeline',
+ `version` smallint unsigned COMMENT 'Version number',
+ `updated_at` datetime COMMENT 'creation time',
+ PRIMARY KEY(`application-id`,`uid`,`timeline`),
+ INDEX `uid_id` (`uid`),
+ FOREIGN KEY (`application-id`) REFERENCES `application` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
+ FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Timeline marker';
+
--
-- TABLE application-token
--
- [`GET /api/v1/lists/:id/accounts`](https://docs.joinmastodon.org/methods/timelines/lists/)
- [`POST /api/v1/lists/:id/accounts`](https://docs.joinmastodon.org/methods/timelines/lists/)
- [`DELETE /api/v1/lists/:id/accounts`](https://docs.joinmastodon.org/methods/timelines/lists/)
+- [`POST /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/)
+- [`GET /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/)
- [`POST /api/v1/media`](https://docs.joinmastodon.org/methods/statuses/media/)
- [`GET /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/announcements`](https://docs.joinmastodon.org/methods/announcements/)
- [`GET /api/v1/endorsements`](https://docs.joinmastodon.org/methods/accounts/endorsements/)
- [`GET /api/v1/filters`](https://docs.joinmastodon.org/methods/accounts/filters/)
-- [`GET /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/)
## Non supportable endpoints
| [addon](help/database/db_addon) | registered addons |
| [apcontact](help/database/db_apcontact) | ActivityPub compatible contacts - used in the ActivityPub implementation |
| [application](help/database/db_application) | OAuth application |
+| [application-marker](help/database/db_application-marker) | Timeline marker |
| [application-token](help/database/db_application-token) | OAuth user token |
| [attach](help/database/db_attach) | file attachments |
| [cache](help/database/db_cache) | Stores temporary data |
--- /dev/null
+Table application-marker
+===========
+
+Timeline marker
+
+Fields
+------
+
+| Field | Description | Type | Null | Key | Default | Extra |
+| -------------- | ---------------------------- | ------------------ | ---- | --- | ------- | ----- |
+| application-id | | int unsigned | NO | PRI | NULL | |
+| uid | Owner User id | mediumint unsigned | NO | PRI | NULL | |
+| timeline | Marker (home, notifications) | varchar(64) | NO | PRI | NULL | |
+| last_read_id | Marker id for the timeline | varchar(255) | YES | | NULL | |
+| version | Version number | smallint unsigned | YES | | NULL | |
+| updated_at | creation time | datetime | YES | | NULL | |
+
+Indexes
+------------
+
+| Name | Fields |
+| ------- | ----------------------------- |
+| PRIMARY | application-id, uid, timeline |
+| uid_id | uid |
+
+Foreign Keys
+------------
+
+| Field | Target Table | Target Field |
+|-------|--------------|--------------|
+| application-id | [application](help/database/db_application) | id |
+| uid | [user](help/database/db_user) | uid |
+
+Return to [database documentation](help/database)
namespace Friendica\Module\Api\Mastodon;
-use Friendica\App\Router;
use Friendica\Core\System;
+use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Module\BaseApi;
+use Friendica\Util\DateTimeFormat;
/**
* @see https://docs.joinmastodon.org/methods/timelines/markers/
protected function post(array $request = [])
{
self::checkAllowedScope(self::SCOPE_WRITE);
+ $uid = self::getCurrentUserID();
+ $application = self::getCurrentApplication();
- $this->response->unsupported(Router::POST, $request);
+ $timeline = '';
+ $last_read_id = '';
+ foreach (['home', 'notifications'] as $name) {
+ if (!empty($request[$name])) {
+ $timeline = $name;
+ $last_read_id = $request[$name]['last_read_id'] ?? '';
+ }
+ }
+
+ if (empty($timeline) || empty($last_read_id) || empty($application['id'])) {
+ DI::mstdnError()->UnprocessableEntity();
+ }
+
+ $condition = ['application-id' => $application['id'], 'uid' => $uid, 'timeline' => $timeline];
+ $marker = DBA::selectFirst('application-marker', [], $condition);
+ if (!empty($marker['version'])) {
+ $version = $marker['version'] + 1;
+ } else {
+ $version = 1;
+ }
+
+ $fields = ['last_read_id' => $last_read_id, 'version' => $version, 'updated_at' => DateTimeFormat::utcNow()];
+ DBA::update('application-marker', $fields, $condition, true);
+ System::jsonExit($this->fethTimelines($application['id'], $uid));
}
/**
protected function rawContent(array $request = [])
{
self::checkAllowedScope(self::SCOPE_READ);
+ $uid = self::getCurrentUserID();
+ $application = self::getCurrentApplication();
- System::jsonExit([]);
+ System::jsonExit($this->fethTimelines($application['id'], $uid));
+ }
+
+ private function fethTimelines(int $application_id, int $uid)
+ {
+ $values = [];
+ $markers = DBA::select('application-marker', [], ['application-id' => $application_id, 'uid' => $uid]);
+ while ($marker = DBA::fetch($markers)) {
+ $values[$marker['timeline']] = [
+ 'last_read_id' => $marker['last_read_id'],
+ 'version' => $marker['version'],
+ 'updated_at' => $marker['updated_at']
+ ];
+ }
+ return $values;
}
}
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1467);
+ define('DB_UPDATE_VERSION', 1468);
}
return [
"client_id" => ["UNIQUE", "client_id"]
]
],
+ "application-marker" => [
+ "comment" => "Timeline marker",
+ "fields" => [
+ "application-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["application" => "id"], "comment" => ""],
+ "uid" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "foreign" => ["user" => "uid"], "comment" => "Owner User id"],
+ "timeline" => ["type" => "varchar(64)", "not null" => "1", "primary" => "1", "comment" => "Marker (home, notifications)"],
+ "last_read_id" => ["type" => "varchar(255)", "comment" => "Marker id for the timeline"],
+ "version" => ["type" => "smallint unsigned", "comment" => "Version number"],
+ "updated_at" => ["type" => "datetime", "comment" => "creation time"],
+ ],
+ "indexes" => [
+ "PRIMARY" => ["application-id", "uid", "timeline"],
+ "uid_id" => ["uid"],
+ ]
+ ],
"application-token" => [
"comment" => "OAuth user token",
"fields" => [
'/lists' => [Module\Api\Mastodon\Lists::class, [R::GET, R::POST]],
'/lists/{id:\d+}' => [Module\Api\Mastodon\Lists::class, [R::GET, R::PUT, R::DELETE]],
'/lists/{id:\d+}/accounts' => [Module\Api\Mastodon\Lists\Accounts::class, [R::GET, R::POST, R::DELETE]],
- '/markers' => [Module\Api\Mastodon\Markers::class, [R::GET, R::POST]], // Dummy, not supported
+ '/markers' => [Module\Api\Mastodon\Markers::class, [R::GET, R::POST]],
'/media/{id:\d+}' => [Module\Api\Mastodon\Media::class, [R::GET, R::PUT ]],
'/mutes' => [Module\Api\Mastodon\Mutes::class, [R::GET ]],
'/notifications' => [Module\Api\Mastodon\Notifications::class, [R::GET ]],