From f48daab37eb1586764270f2bb3608beda67ada9a Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:45:02 -0600 Subject: [PATCH 01/16] Update StatusService, fix missing account condition --- app/Services/StatusService.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/StatusService.php b/app/Services/StatusService.php index 2b3bca274..05f8939b3 100644 --- a/app/Services/StatusService.php +++ b/app/Services/StatusService.php @@ -47,6 +47,10 @@ class StatusService return null; } + if(!isset($status['account'])) { + return null; + } + $status['replies_count'] = $status['reply_count']; if(config('exp.emc') == false) { From 6bc20a37ed0215839e19e2eb56051d39dfe564b0 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:45:57 -0600 Subject: [PATCH 02/16] Update ProfileService, add softFail param --- app/Services/ProfileService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Services/ProfileService.php b/app/Services/ProfileService.php index 43f2ff0e4..abc50d84a 100644 --- a/app/Services/ProfileService.php +++ b/app/Services/ProfileService.php @@ -4,9 +4,9 @@ namespace App\Services; class ProfileService { - public static function get($id) + public static function get($id, $softFail = false) { - return AccountService::get($id); + return AccountService::get($id, $softFail); } public static function del($id) From df444851b5564b15b2667b973c626b90469389a6 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:47:19 -0600 Subject: [PATCH 03/16] Update MediaTagService, fix ProfileService to soft fail on missing or deleted accounts --- app/Services/MediaTagService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/MediaTagService.php b/app/Services/MediaTagService.php index d2457b39d..ef436ec0a 100644 --- a/app/Services/MediaTagService.php +++ b/app/Services/MediaTagService.php @@ -57,7 +57,7 @@ class MediaTagService protected function idToUsername($id) { - $profile = ProfileService::get($id); + $profile = ProfileService::get($id, true); if(!$profile) { return 'unavailable'; From 91ba139808b78208a097b19ddec5a36023a874b0 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:47:59 -0600 Subject: [PATCH 04/16] Update LikeService, improve likedBy logic to soft fail on missing or deleted accounts --- app/Services/LikeService.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Services/LikeService.php b/app/Services/LikeService.php index bc6b876ae..34a2417d0 100644 --- a/app/Services/LikeService.php +++ b/app/Services/LikeService.php @@ -85,7 +85,10 @@ class LikeService { return $empty; } $id = $like->profile_id; - $profile = ProfileService::get($id); + $profile = ProfileService::get($id, true); + if(!$profile) { + return []; + } $profileUrl = "/i/web/profile/{$profile['id']}"; $res = [ 'id' => (string) $profile['id'], From 43d3aa2b94616ffed151b141951c8a206641d52e Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:49:08 -0600 Subject: [PATCH 05/16] Update StatusTransformers, fix ProfileService to soft fail on missing or deleted accounts --- app/Transformer/Api/Mastodon/v1/StatusTransformer.php | 2 +- app/Transformer/Api/StatusTransformer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Transformer/Api/Mastodon/v1/StatusTransformer.php b/app/Transformer/Api/Mastodon/v1/StatusTransformer.php index 3467654af..bfbc3d58b 100644 --- a/app/Transformer/Api/Mastodon/v1/StatusTransformer.php +++ b/app/Transformer/Api/Mastodon/v1/StatusTransformer.php @@ -42,7 +42,7 @@ class StatusTransformer extends Fractal\TransformerAbstract 'card' => null, 'poll' => null, 'media_attachments' => MediaService::get($status->id), - 'account' => ProfileService::get($status->profile_id), + 'account' => ProfileService::get($status->profile_id, true), 'tags' => StatusHashtagService::statusTags($status->id), ]; } diff --git a/app/Transformer/Api/StatusTransformer.php b/app/Transformer/Api/StatusTransformer.php index c44257f81..61c5f875b 100644 --- a/app/Transformer/Api/StatusTransformer.php +++ b/app/Transformer/Api/StatusTransformer.php @@ -66,7 +66,7 @@ class StatusTransformer extends Fractal\TransformerAbstract 'label' => StatusLabelService::get($status), 'liked_by' => LikeService::likedBy($status), 'media_attachments' => MediaService::get($status->id), - 'account' => ProfileService::get($status->profile_id), + 'account' => ProfileService::get($status->profile_id, true), 'tags' => StatusHashtagService::statusTags($status->id), 'poll' => $poll, 'bookmarked' => BookmarkService::get($pid, $status->id), From fc1a385cfda2e8419239b6ee89ca3a8fa03e0185 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 8 May 2023 22:50:49 -0600 Subject: [PATCH 06/16] Update ApiV1Controller, fix hashtag timeline --- app/Http/Controllers/Api/ApiV1Controller.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 1ba73ae8f..1c4254fef 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -3270,6 +3270,16 @@ class ApiV1Controller extends Controller $max = $request->input('max_id'); $limit = $request->input('limit', 20); + if($min || $max) { + $minMax = SnowflakeService::byDate(now()->subMonths(6)); + if($min && intval($min) < $minMax) { + return []; + } + if($max && intval($max) < $minMax) { + return []; + } + } + if(!$min && !$max) { $id = 1; $dir = '>'; @@ -3279,15 +3289,13 @@ class ApiV1Controller extends Controller } $res = StatusHashtag::whereHashtagId($tag->id) - ->whereStatusVisibility('public') ->where('status_id', $dir, $id) - ->latest() + ->whereStatusVisibility('public') + ->orderBy('status_id', 'desc') ->limit($limit) ->pluck('status_id') ->map(function ($i) { - if($i) { - return StatusService::getMastodon($i); - } + return StatusService::getMastodon($i); }) ->filter(function($i) { return $i && isset($i['account']); From 175a848665c38fe035bc37aec326b78b30218628 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 00:21:46 -0600 Subject: [PATCH 07/16] Add /api/v1/followed_tags api endpoint --- app/Http/Controllers/Api/ApiV1Controller.php | 47 ++++++++++++++++++- .../MastoApi/FollowedTagResource.php | 33 +++++++++++++ routes/api.php | 2 + 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 app/Http/Resources/MastoApi/FollowedTagResource.php diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 1c4254fef..d142575c0 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -19,6 +19,7 @@ use App\{ Follower, FollowRequest, Hashtag, + HashtagFollow, Instance, Like, Media, @@ -99,6 +100,7 @@ use App\Jobs\FollowPipeline\FollowRejectPipeline; use Illuminate\Support\Facades\RateLimiter; use Purify; use Carbon\Carbon; +use App\Http\Resources\MastoApi\FollowedTagResource; class ApiV1Controller extends Controller { @@ -3644,7 +3646,7 @@ class ApiV1Controller extends Controller return $this->json(StatusService::getState($status->id, $pid)); } - /** + /** * GET /api/v1.1/discover/accounts/popular * * @@ -3802,4 +3804,47 @@ class ApiV1Controller extends Controller return $this->json([]); } + + /** + * GET /api/v1/followed_tags + * + * + * @return array + */ + public function getFollowedTags(Request $request) + { + abort_if(!$request->user(), 403); + + if(config('pixelfed.bouncer.cloud_ips.ban_api')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $account = AccountService::get($request->user()->profile_id); + + $this->validate($request, [ + 'cursor' => 'sometimes', + 'limit' => 'sometimes|integer|min:1|max:200' + ]); + $limit = $request->input('limit', 100); + + $res = HashtagFollow::whereProfileId($account['id']) + ->cursorPaginate($limit)->withQueryString(); + + $pagination = false; + $prevPage = $res->nextPageUrl(); + $nextPage = $res->previousPageUrl(); + if($nextPage && $prevPage) { + $pagination = '<' . $nextPage . '>; rel="next", <' . $prevPage . '>; rel="prev"'; + } else if($nextPage && !$prevPage) { + $pagination = '<' . $nextPage . '>; rel="next"'; + } else if(!$nextPage && $prevPage) { + $pagination = '<' . $prevPage . '>; rel="prev"'; + } + + if($pagination) { + return response()->json(FollowedTagResource::collection($res)->collection) + ->header('Link', $pagination); + } + return response()->json(FollowedTagResource::collection($res)->collection); + } } diff --git a/app/Http/Resources/MastoApi/FollowedTagResource.php b/app/Http/Resources/MastoApi/FollowedTagResource.php new file mode 100644 index 000000000..3c690d05a --- /dev/null +++ b/app/Http/Resources/MastoApi/FollowedTagResource.php @@ -0,0 +1,33 @@ +hashtag_id); + + if(!$tag || !isset($tag['name'])) { + return []; + } + + return [ + 'name' => $tag['name'], + 'url' => config('app.url') . '/i/web/hashtag/' . $tag['slug'], + 'history' => [], + 'following' => true, + ]; + } +} diff --git a/routes/api.php b/routes/api.php index f05489c7f..2c35d2e06 100644 --- a/routes/api.php +++ b/routes/api.php @@ -89,6 +89,8 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::get('announcements', 'Api\ApiV1Controller@getAnnouncements')->middleware($middleware); Route::get('markers', 'Api\ApiV1Controller@getMarkers')->middleware($middleware); Route::post('markers', 'Api\ApiV1Controller@setMarkers')->middleware($middleware); + + Route::get('followed_tags', 'Api\ApiV1Controller@getFollowedTags')->middleware($middleware); }); Route::group(['prefix' => 'v2'], function() use($middleware) { From 4d997bb9599d1efdf0cb55ebe8bd3123b9947c19 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 01:08:09 -0600 Subject: [PATCH 08/16] Add /api/v1/tags/:id/follow and /api/v1/tags/:id/unfollow api endpoints --- app/Http/Controllers/Api/ApiV1Controller.php | 85 ++++++++++++++++++++ app/Services/HashtagService.php | 5 ++ routes/web.php | 1 + 3 files changed, 91 insertions(+) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index d142575c0..d7139ea21 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -70,6 +70,7 @@ use App\Services\{ BouncerService, CollectionService, FollowerService, + HashtagService, InstanceService, LikeService, NetworkTimelineService, @@ -3847,4 +3848,88 @@ class ApiV1Controller extends Controller } return response()->json(FollowedTagResource::collection($res)->collection); } + + /** + * POST /api/v1/tags/:id/follow + * + * + * @return object + */ + public function followHashtag(Request $request, $id) + { + abort_if(!$request->user(), 403); + + if(config('pixelfed.bouncer.cloud_ips.ban_api')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + $pid = $request->user()->profile_id; + $account = AccountService::get($pid); + + $operator = config('database.default') == 'pgsql' ? 'ilike' : 'like'; + $tag = Hashtag::where('name', $operator, $id) + ->orWhere('slug', $operator, $id) + ->first(); + + abort_if(!$tag, 422, 'Unknown hashtag'); + + $follows = HashtagFollow::updateOrCreate( + [ + 'profile_id' => $account['id'], + 'hashtag_id' => $tag->id + ], + [ + 'user_id' => $request->user()->id + ] + ); + + HashtagService::follow($pid, $tag->id); + + return response()->json(FollowedTagResource::make($follows)->toArray($request)); + } + + /** + * POST /api/v1/tags/:id/unfollow + * + * + * @return object + */ + public function unfollowHashtag(Request $request, $id) + { + abort_if(!$request->user(), 403); + + if(config('pixelfed.bouncer.cloud_ips.ban_api')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + $pid = $request->user()->profile_id; + $account = AccountService::get($pid); + + $operator = config('database.default') == 'pgsql' ? 'ilike' : 'like'; + $tag = Hashtag::where('name', $operator, $id) + ->orWhere('slug', $operator, $id) + ->first(); + + abort_if(!$tag, 422, 'Unknown hashtag'); + + $follows = HashtagFollow::whereProfileId($pid) + ->whereHashtagId($tag->id) + ->first(); + + if(!$follows) { + return [ + 'name' => $tag->name, + 'url' => config('app.url') . '/i/web/hashtag/' . $tag->slug, + 'history' => [], + 'following' => false + ]; + } + + if($follows) { + HashtagService::unfollow($pid, $tag->id); + $follows->delete(); + } + + $res = FollowedTagResource::make($follows)->toArray($request); + $res['following'] = false; + return response()->json($res); + } } diff --git a/app/Services/HashtagService.php b/app/Services/HashtagService.php index de58fae59..9c455deb0 100644 --- a/app/Services/HashtagService.php +++ b/app/Services/HashtagService.php @@ -64,4 +64,9 @@ class HashtagService { { return Redis::zrem(self::FOLLOW_KEY . $pid, $hid); } + + public static function following($pid, $start = 0, $limit = 10) + { + return Redis::zrevrange(self::FOLLOW_KEY . $pid, $start, $limit); + } } diff --git a/routes/web.php b/routes/web.php index 6f5d1fc33..73bc7c24c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -407,6 +407,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('web/username/{id}', 'SpaController@usernameRedirect'); Route::get('web/post/{id}', 'SpaController@webPost'); Route::get('web/profile/{id}', 'SpaController@webProfile'); + Route::get('web/{q}', 'SpaController@index')->where('q', '.*'); Route::get('web', 'SpaController@index'); }); From b4ad6668e9b8e1d0357ac003eb057ee84e52e2fd Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 01:10:09 -0600 Subject: [PATCH 09/16] Update api routes --- routes/api.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routes/api.php b/routes/api.php index 2c35d2e06..4805e84ed 100644 --- a/routes/api.php +++ b/routes/api.php @@ -91,6 +91,8 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::post('markers', 'Api\ApiV1Controller@setMarkers')->middleware($middleware); Route::get('followed_tags', 'Api\ApiV1Controller@getFollowedTags')->middleware($middleware); + Route::post('tags/{id}/follow', 'Api\ApiV1Controller@followHashtag')->middleware($middleware); + Route::post('tags/{id}/unfollow', 'Api\ApiV1Controller@unfollowHashtag')->middleware($middleware); }); Route::group(['prefix' => 'v2'], function() use($middleware) { From 521b3b4c826e95447e7e361481059b47ee1e3df5 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 01:25:39 -0600 Subject: [PATCH 10/16] Add /api/v1/tags/:id api endpoint --- app/Http/Controllers/Api/ApiV1Controller.php | 39 ++++++++++++++++++++ routes/api.php | 1 + 2 files changed, 40 insertions(+) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index d7139ea21..4e13fb312 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -3829,6 +3829,7 @@ class ApiV1Controller extends Controller $limit = $request->input('limit', 100); $res = HashtagFollow::whereProfileId($account['id']) + ->orderByDesc('id') ->cursorPaginate($limit)->withQueryString(); $pagination = false; @@ -3932,4 +3933,42 @@ class ApiV1Controller extends Controller $res['following'] = false; return response()->json($res); } + + /** + * GET /api/v1/tags/:id + * + * + * @return object + */ + public function getHashtag(Request $request, $id) + { + abort_if(!$request->user(), 403); + + if(config('pixelfed.bouncer.cloud_ips.ban_api')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + $pid = $request->user()->profile_id; + $account = AccountService::get($pid); + + $operator = config('database.default') == 'pgsql' ? 'ilike' : 'like'; + $tag = Hashtag::where('name', $operator, $id) + ->orWhere('slug', $operator, $id) + ->first(); + + if(!$tag) { + return [ + 'name' => $id, + 'url' => config('app.url') . '/i/web/hashtag/' . $id, + 'history' => [], + 'following' => false + ]; + } + + return [ + 'name' => $tag->name, + 'url' => config('app.url') . '/i/web/hashtag/' . $tag->slug, + 'history' => [], + 'following' => HashtagService::isFollowing($pid, $tag->id) + ]; + } } diff --git a/routes/api.php b/routes/api.php index 4805e84ed..b3746a85c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -93,6 +93,7 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::get('followed_tags', 'Api\ApiV1Controller@getFollowedTags')->middleware($middleware); Route::post('tags/{id}/follow', 'Api\ApiV1Controller@followHashtag')->middleware($middleware); Route::post('tags/{id}/unfollow', 'Api\ApiV1Controller@unfollowHashtag')->middleware($middleware); + Route::get('tags/{id}', 'Api\ApiV1Controller@getHashtag')->middleware($middleware); }); Route::group(['prefix' => 'v2'], function() use($middleware) { From 1a83c5858d7c10b8f08b38188a18c81e38797e30 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 01:43:58 -0600 Subject: [PATCH 11/16] Update settings view, add fallback avatar --- resources/views/settings/home.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/settings/home.blade.php b/resources/views/settings/home.blade.php index 702373c83..2c02cdde9 100644 --- a/resources/views/settings/home.blade.php +++ b/resources/views/settings/home.blade.php @@ -8,7 +8,7 @@
- +

{{Auth::user()->username}}

From ed3521416112f6e8661cb2cae881a9e3abf35afd Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 02:05:23 -0600 Subject: [PATCH 12/16] Update HashtagFollow model, add MAX_LIMIT of 250 tags per account --- app/HashtagFollow.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/HashtagFollow.php b/app/HashtagFollow.php index 0503330b0..126701fe1 100644 --- a/app/HashtagFollow.php +++ b/app/HashtagFollow.php @@ -12,6 +12,8 @@ class HashtagFollow extends Model 'hashtag_id' ]; + const MAX_LIMIT = 250; + public function hashtag() { return $this->belongsTo(Hashtag::class); From b5fe956acf050dafd84bb912bde332a951a65fe6 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 02:13:26 -0600 Subject: [PATCH 13/16] Add `only_media` support to /api/v1/timelines/tag/:id api endpoint --- app/Http/Controllers/Api/ApiV1Controller.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 4e13fb312..03b2fa3a1 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -3248,7 +3248,8 @@ class ApiV1Controller extends Controller 'page' => 'nullable|integer|max:40', 'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, 'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, - 'limit' => 'nullable|integer|max:100' + 'limit' => 'nullable|integer|max:100', + 'only_media' => 'sometimes|boolean' ]); if(config('database.default') === 'pgsql') { @@ -3272,6 +3273,7 @@ class ApiV1Controller extends Controller $min = $request->input('min_id'); $max = $request->input('max_id'); $limit = $request->input('limit', 20); + $onlyMedia = $request->input('only_media', true); if($min || $max) { $minMax = SnowflakeService::byDate(now()->subMonths(6)); @@ -3300,7 +3302,13 @@ class ApiV1Controller extends Controller ->map(function ($i) { return StatusService::getMastodon($i); }) - ->filter(function($i) { + ->filter(function($i) use($onlyMedia) { + if(!$i) { + return false; + } + if($onlyMedia && !isset($i['media_attachments']) || !count($i['media_attachments'])) { + return false; + } return $i && isset($i['account']); }) ->values() @@ -3873,6 +3881,12 @@ class ApiV1Controller extends Controller abort_if(!$tag, 422, 'Unknown hashtag'); + abort_if( + HashtagFollow::whereProfileId($pid)->count() >= HashtagFollow::MAX_LIMIT, + 422, + 'You cannot follow more than ' . HashtagFollow::MAX_LIMIT . ' hashtags.' + ); + $follows = HashtagFollow::updateOrCreate( [ 'profile_id' => $account['id'], @@ -3949,7 +3963,6 @@ class ApiV1Controller extends Controller } $pid = $request->user()->profile_id; $account = AccountService::get($pid); - $operator = config('database.default') == 'pgsql' ? 'ilike' : 'like'; $tag = Hashtag::where('name', $operator, $id) ->orWhere('slug', $operator, $id) From 0b42fe0f005bc061b144d71cdccab1f5a62d77d9 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 03:22:28 -0600 Subject: [PATCH 14/16] Update HashtagService --- app/Http/Controllers/Api/ApiV1Controller.php | 18 +++++++++++++----- app/Services/HashtagService.php | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 03b2fa3a1..af46f8af3 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -3249,7 +3249,8 @@ class ApiV1Controller extends Controller 'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, 'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX, 'limit' => 'nullable|integer|max:100', - 'only_media' => 'sometimes|boolean' + 'only_media' => 'sometimes|boolean', + '_pe' => 'sometimes' ]); if(config('database.default') === 'pgsql') { @@ -3274,6 +3275,7 @@ class ApiV1Controller extends Controller $max = $request->input('max_id'); $limit = $request->input('limit', 20); $onlyMedia = $request->input('only_media', true); + $pe = $request->has(self::PF_API_ENTITY_KEY); if($min || $max) { $minMax = SnowflakeService::byDate(now()->subMonths(6)); @@ -3294,13 +3296,13 @@ class ApiV1Controller extends Controller } $res = StatusHashtag::whereHashtagId($tag->id) - ->where('status_id', $dir, $id) ->whereStatusVisibility('public') + ->where('status_id', $dir, $id) ->orderBy('status_id', 'desc') ->limit($limit) ->pluck('status_id') - ->map(function ($i) { - return StatusService::getMastodon($i); + ->map(function ($i) use($pe) { + return $pe ? StatusService::get($i) : StatusService::getMastodon($i); }) ->filter(function($i) use($onlyMedia) { if(!$i) { @@ -3977,11 +3979,17 @@ class ApiV1Controller extends Controller ]; } - return [ + $res = [ 'name' => $tag->name, 'url' => config('app.url') . '/i/web/hashtag/' . $tag->slug, 'history' => [], 'following' => HashtagService::isFollowing($pid, $tag->id) ]; + + if($request->has(self::PF_API_ENTITY_KEY)) { + $res['count'] = HashtagService::count($tag->id); + } + + return $this->json($res); } } diff --git a/app/Services/HashtagService.php b/app/Services/HashtagService.php index 9c455deb0..87f895a65 100644 --- a/app/Services/HashtagService.php +++ b/app/Services/HashtagService.php @@ -28,8 +28,8 @@ class HashtagService { public static function count($id) { - return Cache::remember('services:hashtag:count:by_id:' . $id, 3600, function() use($id) { - return StatusHashtag::whereHashtagId($id)->count(); + return Cache::remember('services:hashtag:public-count:by_id:' . $id, 86400, function() use($id) { + return StatusHashtag::whereHashtagId($id)->whereStatusVisibility('public')->count(); }); } From bd30e671cc460bc321c2aa872a80316f14508a23 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 9 May 2023 04:05:26 -0600 Subject: [PATCH 15/16] Update compiled assets --- public/css/spa.css | Bin 7815 -> 7835 bytes ...iscover~hashtag.bundle.279c3460159d3af7.js | Bin 0 -> 52278 bytes ...iscover~hashtag.bundle.76807a8ff71bd205.js | Bin 51774 -> 0 bytes public/js/manifest.js | Bin 4282 -> 4282 bytes public/js/spa.js | Bin 213166 -> 203425 bytes public/js/spa.js.LICENSE.txt | 2 -- public/mix-manifest.json | Bin 5977 -> 5977 bytes 7 files changed, 2 deletions(-) create mode 100644 public/js/discover~hashtag.bundle.279c3460159d3af7.js delete mode 100644 public/js/discover~hashtag.bundle.76807a8ff71bd205.js diff --git a/public/css/spa.css b/public/css/spa.css index 954390148e31b0112082dfe035a1dbd40821201c..8d2e319582de4522dc3567d730740bdd170f02ac 100644 GIT binary patch delta 23 ecmZp-oo&0}i#V5cm2PHUN@|6b(dJj;bJ+lJ0|_4h delta 16 XcmbPj+ittzi}>U{(%hScB|6vuJfj9V diff --git a/public/js/discover~hashtag.bundle.279c3460159d3af7.js b/public/js/discover~hashtag.bundle.279c3460159d3af7.js new file mode 100644 index 0000000000000000000000000000000000000000..f5a6ff81eb1058903cc54d71633fae2d5064d329 GIT binary patch literal 52278 zcmeHw4RhN@lJ;MLk*q^rK!~IyN`k^Dj*ej@BA!2e8m;DYJbWeJ-7pIhKZ}#|_wV&D_E%r&r}nuXOXe_3;zh%tj?eRa zlBw3Gn6yp%5MA11Jpuirg=ymjhEy>A=f!WqBy*QZoW(R#H;Z5Li|)jq(*oUe9!>x` zr#I-H+R_}Ij)SL9Gj|e47-luW0-iqY1mn^ZH}V%jm*?`MzvOq`zqelo8GmeC7&m^F zT&@;Dl%?vGz5m}i^L`EAf8UKVd^&zV7`@*gcJcA~++Qq%Y4?nw^XZj^%niay zD_hiEXIDvlV@1J@^$S+~_aupvj{SXf?a#xh24jSKg9ktn0ikJ z4yH5<=Ye+}V^jLh#E?%y%aEisPqRi{xIkR{^k8jWsb)foN`0u`-s?h<61+_(=#-yd2D9o^D&W)c< zuDtc9NxaGe&kpg}##_9v1X+AH-=)3E#?-?pccWH2#w4ckjr%6O@{?ft4Z!4rrzVd7 zE{s$6GRQjip1%zDt_OQqPr7G+t{1aj`iZ~5P;an*gS)$~n_UG_r;|?@JR)-yAjZB+ zTX5Iyg3K}TaewN_5rG005<>L0=_25go|Jf z?wb;fnm{xU7ub&DelwI5c?gJ}K9#?U(#|@v5CuRii}6H#eN}4P8=MoCJ?VELy~@k4 z0O!eo*4nsX2HuZ(zuKUtv0s2~fS#cUrj@PIUz2$O#a!Ikd*L3$^xiT~GlCW-O(c;l z{OmbXNRC4JE7r5+(p_cY+?93^1RxKROb&1)NOIyVhU>1YIA5mW_wPG`$|cIC)qKbf zV^`jQn{ki4LyqkELCc;q?^KNON#}{|(t4D_X$>vxI+=eShIhbk8?_MYb1#`r$B z_vA&piGb1|`vu$pOu52l6e9%wD%LM_lYdo`fC1|q_WQz&R*^LLn5)raJa|0=V!C>H zjqACCU^_k;9`<)quT!YkqA{f7b&CWiVdb?5F^qQS3{U#Q;r)jLLP0@!WmEt5d7J() z&$S2t8saVab%|*P-$&Enod-T*Jp0yAEzIXHlHfWFZVb7vC3w6HqJpY&q6%iIYj*Hs zJoV>pdKKT0R$%_}d>*I4&OKZ~kLrMzkg8(#!i#~DSNnlhG!|v4I&J{v%b>g3tM~8o zWfm-pE(;b@g~rdp%$>k~c-y{|><-#lG@S>}jO{7wzdIWpQQvA%o2S*NwrDomte$zOP%t=O@K?gmBt!y zcflNbBrO)UOMRiVrqo>Mnr2m5AvdBGf~)`YCW0th21$0?u}R&xwK;fNo-Hq-rK8GR zH!ZBCht}o7>WF4xviNmL+^Rqn6VVCsiixV$9s5}lShw-YN>}Q`jSp=crso9YbIHFY zmY}hvaM zQkKj9gtfqQZ^dl)4QOWyY7PB)YQqd~P;XlVg~BwYRI6_lx?^t2CPK}EVUkON6ozXG zFA>&Eu8PtFmyMLP?YSCq%g+icpFS0P>7S5Luz#9IQa!%vpXUY=u?!Z8hX?(m(T9q} zb-I8NrOfuP;}~XHcwt z(=6I7Xw|6A^rcq^gTe9fPAf27fW!W1cp@&q(edzPBrd?C(E*+oe!m1(i}w2^V_VBf z@X?Cn&Q95bSN(z5HGA;R^s7dPs*CKdpz~t1?CH}D!lGK1nDFRmvABS9Ni#-_m4ekWYWOTOYY#@&Puy?sI?GAh2dTX6GC{v}1ym_+LqSYR_bLD&Wd}wORZkAhxGj>2{ZDH;`3eC%U=2C-w z!7J~=>uD%6U~*c0^~Zx#{|hMW;?vivoDYvQ6HPFdxJTXs=y7I#f%G`_|28~}6_2M<L-8Cozp@@QLQgw%e#>*xa-_w#>8^4_|kk8KpIC=?O`D1;Q(wI zxCHT|pC}+<@Hdhp5*UEB%g`VycLGv|4Gu=)=SiR?l>`Zhv(fXw4Wr3?H3b^m9vJ}& zfe<(iFyth7hQQul=L`R=d*;2q`P}Qgo~{SScVBkT_AX6(Sre$QVt@nK2NG~XED&L) zi~eWTRq3n=PB*`Z6G=RJWS}O@;Y2)tfvoFHMrG+5V>o@9}rr^5@yu{!IHTQz+QQK+b2jm4zAg^%(*k;?k@)Ns~#f!77>4+hjcS zu-lgus@T|w9PDAeA9?&nb$1g^v#YT^7}?fUKw&ZYj8#$0WNh<(>uUiaQi!eM zDV2TC)18Umcu#b`bUc@wH9FRuNZU4jVfdnjH+$0Sj|Veo!Pwfmp;s=B}t=WP`)24#f!u z6&q8~ozy#uA9yy?iH-Oj1RS-dpo&=3O7a@qLfm1KRg%Ea{sps!SL|ZGO0>J})1>N= zbIFfMu1WE1{S@51fOFl%4MswFQQA<0vRjj)3>2a(UIU?vnyucZD5y&s%xQWPQh*T+ zCI}eXSBNHpD@n)+wv>M+Zv@b*J2s{Z8F6JpOC-l<2_yA8-O~$*qPM5q9rOOYzdbD! z_T>3}x>wql?tw5~q8`xN5K*W1F@0j zbF@Dg9-C=Cg<&5O&M7*~Nd}J~A;o1}Pv~Kr8L$1DCG?2ld@9zeQY*ot{}(3o$V&fh z6MAI&A3dQb&J%i+pjP&)pay8oH1?X3cvwrkiswjfD$;#gvvw#N4kOLssJG77DaWVD zY%nqz=xdlFI7G}|<=e2*uakem^zX>Qx}|oY;NQ4zBNS_1QML3iRxM`4|6b6U*C|v19q|xrxA&((zLX0&cEb~<0vz=RV$?Ltki6o z%V{+ULg!LaCQ!*cYdd)+kfc1EKw>ob-pPP~m#Qt*0c)X5Nb+U_{uxqmb;=7py0tHTb`5z zWb^`!TQ(i0fkEk#Pcb+Q_9dZ0DSSVb;tRR7?yk2fxaGc8SX>i5c6NIz(i0}oGP^?H zhiKG*w{}gG+tIQgK$yfa%UMdzq{`&L7QdiKPPGbGa#mx`7?9SqS)DWzd8x}(2iX3i z6b9nhnyA&5?iF_6!v_U?8U^pb>yY43qnb~^k4K^(m|7%MPTyjRB zVrA?sAU6||u5_Xxg1liuIlwv9V)klWvYCjvx>ulc==qK*sZ>zC^jhn4nCW=uKikYRn=du1$mArPXpOMt@4=R?z643EV@~BPJe7+1C(P;NDOKG{*mq`|C97R$8h$K467gxJqCM(b^?N%Okfe^0Vn|%bSVz^Y|Tm z8eT*7k`8e$Ax%9S;*qk>ImE+B^uV20%}wE)%#cM*@tpYz3Ga)nx8L3x5ySQ$C-J8mUrE;ElLMzT$UQ(WWyBvWNKaT z;fP+}f{uoq_FlTM78h8R0{YAB7CylAm3%Jw-sPdY5J?tsxU}8_tpcd_26<%~0OjSF z3&DbnJOm`R=`2=?xrqL$|7yk#_-ZiZtqBYlt1N?dU!ly4EVA%lkM{=$bA(RiMTNK) zBCg;R)7~))uOGyeo&W2P#TgACDkRKPOvI&1IL}d_A`tSl=n2avB_VPWA~g}95ETt-5@PII zNXKWL4eb3Jom&g>r4=T6yb2y$4I@FobSTp$*Y zM1-=ur07eJVBdrFct7r2f3D0N1Cfvz>#?KC+e&wL&r z#LM7Orr{tE*)~=3aiMal4y91oK7=@@&F1_1ZB=evRyvrEO-P;%-J%D-vJ;n=@%Pk(v0UO znf6G7QEf(1?-xA+H}+!(85v9~Y>;)a8v#!&J((V18P zjD$XGp1?-_n;(m7=Ss2)>o+7hgtJ@CaSRRiPz`jEs{za#umBRwO2dL2DJ_Cr^jeC* zMM___;?#@?jbfx_R%${GoJk;~#l^8`pQ4Owa4nFgS7rjp0udvqVkyL^BM>4cVE5e- zQr6+R=`l-%&2Z4~lhL3xF=A7&q!*WaP~8AXq~}uJ^4|1qFXAku-olT1i#UoWNWNTv z{a?eZui{uufkw1ox|0H}aE??fC52O$&XnI$%pA&q!Zy8G-Ud*Udt3QHB0J;r}vl z^Cb*_*j4X(;tQxyw)O#J@sb<>%Xd~9Qz-^GsXILkPem30oq3#ewP#>8udn~+Gt+67SBh9EFFm$b{gxxpaQJ#$!Yas7(haY{_)l8h- zfB;sFB-6(P!w-}j`bWZnL+!|W+6@3ph^yWtOc11dOei4B>yLzi>GemVI>Z66bqhT} zZoun8>fqzh!?QU~1R`fwDSCeZMJO)|M+3<5N@W&y0tGdGOi;W~zIX!`TK#1e;2hF% zzdzjn-NoYtbTXWt2Ad^6fGtNl;9|CQ5 zF4m7%vwyK75*qY5Ws5W@o6Tw|Nz6W@eLqUOMos!L49X1eOrqTx* z1UNIQ$vj?7dn-QGOVqkAj)=0{tqF2-9I`KH5SR~$zkGw`$w6M^isQ&{oFEe(4rKmD zeC!@Qvwzq$U3Bb1hWZgU5>>GBRm_J{r4Z=UGa)Q9#=}G;G*oFuC$5ZUjG@+QNk^22 zKYlHo*BjgmJ%l8exlPlEqX=@5tDt6_Uf^g)5JV-_uVi~R^k!}cV057NytZuu(3;1i z9NIDr)+6Qz0`2FLt!=_e;0c4Zs$n*&%gT|6+$k8nxi3+DRi_$zGt{4=d~`mCrWNdR zkj*JiP^+$FJtHDP5=tnB{CX8^djRNaK+7>+X(?sAz9&$I!xB)`*Lwh^bONDp5it48eBO6 zV4f#r8Vk`bI*;Nv!aS9yFqcbh>mk2ngFXU>2gl-@{Zi;(I2i>Mv}?J#`~@Ja{fYZS zf_omYS-yLMqp&!=hKd^n!=*;%^BR*qV5cOx6)8zYvxe3w5(q|Y><}tH#1EIlleLMD z2TDpYA0m>ZHDqaDi>AS=oO7Wb`|;vSwDIQilp3CCdCl8NKbnX9p}`uVXFW zsDUMMFt}htp!e+wL9+K-6M`sgq-1Erz>*ZirUuWUYIHQbskky?kO&P!T;X)u9Fc_U z+?ms$n=?h$ZCD7 zxG=U1?CL~xus(|7?l3D?A>RGaU9`SAw|*HFS1vN+XQO**^XK?X0e z_?*9sYpXnWLN@A`Yj+?mhWRqT@l~FP!wR=v`U$wi*O- zRgDKy@*g}KRTE+l2gK{spn+~_2E=l>3Z%(h8n{~y3;YIeDDq8vQ{WWjVN-2)pj?>_c$d48@XEOgrKc~tcIaC zo8b-SMH>q0D4gjuwsF9UlD}W+_vTM%wnU>+?onUSqBKeb3jn#mBMbUh6Eb`#WpQ1o~4@-2PQM1KFyp4gW5SAm!ofV zD3FqP8tG;i5LRP}j|S0d#}5NA9d<#ev4C(X2M0{!LmqSw=y(?eN?BQiK$5?fO;#=U={Ib(!D6rQh1qhZUKnfpg-uWJtXl(+Z~Q5|<2&()j|Kjk0aKH8xuM6C-J2p2^dd%PqBgG!(>lhBMNfX6s2e@3|E;rmTLg%F8Rf9B@oUPbhfj{UtuGAQJCe(HW}^sp!`31);#fp9=wyWilQ z{)x^n0`2G@%Bu43_W|d909W$$G2r%jRJjcC9;4D$V5>KQIrqrg{|c-i;-DSLJj;(P z9?!L2AgQZD?V)rPEBKbR1L8T{~vT4bJA>z0zd)Evb4rktS zL0%}a|56v^Kmc2~3)6z;Yatyng^qcqQdnzR6Js-vnTyKYu+X8eVyx$-gj|B{Jy=`= zHOuIf=0(ea&mMMbnSgYZnln@LyrO>vb4(7aj1j`(_}s7GTi2r}8zt>Mc8v3I6;3ov znVe1-v90%Sp2~ zXQ9dluVdN zoQLKz-2*X7Zk)0VYi2Ur^M5E~8Fc_|P(BIg^a7-iG-iWYMjjavWczTO^+6{Pb+w)b z48C_rP)ZrexJ|kWQ}VVtJ3qz7tx6T_mqXgR=129gHZ8Yo=~B8!I8jGQ+QlptVL}dM z1!WOZjT6uQCAaCn>NK;Y73f9Dq_7VI!L7>852pMY6L1!Z+q6DsQlP z6yIcN#Heu|%&S`HLQfv(oVxERBJW8E&w zmlakAvk)hz6t8PW1%{G7(l>lp2{M@=!uvJd2id(ti&cPHo`)HF&nt4(+zKY0xstw|^^&~MSH zVWlCxmaR0U`MJ#yq1t0qj_?Af0+({AN!L|^hKQ6*bB_8%CXQyJme3_sekc?25?3}S zV;PCHF&NDSF#@>HJX=bZ=Hkpai=|Iz#C%^|>10(dStO;`e8({?_ zlk1NvfEaE6Yc#n0Qks9aZN+sz>e7sDrnaPOAU5`4n}))?d~uIkQpXhB3SP63 zc2Fqj5}fI;EIR}Qq=BIl^oQ?-bmP|b<6WExTIo`0+<)cmK)Gv5UlWPGA&$^$k{Sth z0?s{LV~_Ght!nXfVMyjSYJnGoyasFpxxb|VYk4$j%i_k5X zg(b^?#^Mn1jylc`oW=dy@4Q^I6D!B~#v2}wx<26j4G_6k~ zxdFo@_zl^LzYh%myznE)X-Kr;Ux9sI7+oVB^DoV_1q7_|l-SN1IZ6MVK1^waRwNwfQ_(h01vqosi@-ulz*K2K< zOg>@7fE%JI671R(MApth4J$d)JjIPzWmti?$n{`Ql!`Vw@-* zsx2VHC<0XTptL5g@>_p`NOY0EmKWVYP3aJMVXS4)(R)?L}8+-+PJ*Au~wg468E zEcO8QVTZR){ts68zx%5^$?A>L!*ICiI2>fXY=XHv?%*f!cV z%cVMVcVqx;cn48-s+_QK>$dh`*gvIu3>$j|Bnd^NLcKbI(KRu8^Te%XZHKljRcLa} z7TL^Sg!5akhcR#&KzfV(@P+d=)r0@hpSBf%WV6&d)IrA$GnC=GOtT z#C+!&nBd$=f!|0TPr}(L_nU_Q9RSgm@8ql84d)&8`wHc$*cZ@VC*HcFQ`S(JPADbQ zTM_+Dka^sIZ-b+w{q~&2kAiR4xK25F#b;Ztdy~Uia4?$=&#Q!oWBGUa#isSv24v7u zLqZW&58A<qr z(~5|3&w2%Q37HkX@Cg}@%8Kr|0FSe2+MvxjUp;O@K;N-X%cV12Yeh>i!1;6=tFOXl zIFHVgti@AN2dHl3mhM}*dlLgM5ft&g`vRzKG$;;P$7OCQ3+QStL`7XaK)!V4i54i8 z@jraE3b;*cHicG=6hu6edgP%RFYaQST!lDAkz=wYb#K?qBnx@5aZj3iGM{SLfcO|S zbDq~suiGZ+p&*l*x!E&cGq-!!VcIb|>J~82eTqn^P54x4zUt@Ns1>q=F4?dP`Vn1i z0M%CD&EncUB6X=<5I6NkIf=NQFqy86+*Czbjl<_JSgvH7sx^Csm=H#**2;L+#BH^P zdqmtv>8K15&poDP2wBswyUoKWHED1o?+W)o;c~|Q-yBk#9rr}f#hCCX(;yfIqXPZ) zMkxV%*ry38Ip5b4r}E;OD#-%SwL$$0Tv>!`bx&nA14w$c7<%L0i{aXqYuwIz@iv5= zO*i$X3takiMRpC$S7>h`)U4@gBfI4GN}zm;cdchPL5lN1uU}h-*0)Iz2%k&&2IdHg zn?IK)*hDst&1Z_LamCsxb7WkszrZBWyxwFWf|_5pX38Ie|0wS_j4gjLe!FsDMzmm5UrL0883STbAma0rFcQjYt5 z16j?zaF45NJk_Yfz?Zup!6gRB=cdz=e`n|}W_Be;Shc~xv2055gb0>%bDv;OT z#f)g0BHP!sIr39;lJsDw2|+&5yoxfY>pIifu_Ki#q05arTd;`7wThdd;Zs0uRRNG9 zDQsxt*rc;74ZvV($|+Gc3bwuPwkafQDNXFHBGh&)EV@H*H1?zRf@_ds$_|glL9|4o zsug5;rn%-u2TD#Wm9{+iQ6{JeELU=vctB=;!BDLszV0@j z(lgBUdLV3f9#imo*0^#z2jtA{k?jPSMw{e`xIK)`^uQ@od?k!Tj^_vcK;;{EE?#WUv z)OYIen77aSS)3;G=vte6e|xtcdqeep<9j;6so(jj{Gr-G0(y}Nn`YyATIA&K=1gnj z+v0s+=gOY017F(omXYOMK7+b8aHQ^!Jw80xaHiMXx!8y~ob2x(89@gp90whaUUZ#g zybi(L6DU+HGI`sRJ2klio?lV1hQ$F_eMhAnzBTWxJx5u8{QUCCfCU=5TVvmb<2S-Q8 zk25*ujE_FOFQiB|J@@qb+x)t_+nO^T@K5c9tGVvmnTBdjn2V;bxq0eK&~ z)}!I*c=)l`dNev1?#A!TjXfM52s7>+5#l~{t%3|6Ydeqj2gBV0GUgJ8!~MgN+RhP5 zE}>~Qq(O$<7aoTJ0XL|9wLvTUYPgG7&yH(hIP%0Y8a zkNQW7LWjqF;!F?QR1o^$_;~*@SDf=CW3Au*Q2gidWRJo$vJsuwKKLS5GJ~;#n zSL)NpBi4h%`|~4Qaz8?4Dq8Fa90_#$(4B<@01yAji)Ep>6WyAr35TPj0k$)05T$8N zl#&ExQJNZ}G|~$T$Eg;UcMeIddr#*0WO&GER+sA!nheX8d(UQg(jPJ&Jo0P?qx)x& z93J!u5g&bT%;)Yso6!g;{1Ntv8PUCGbFhCT zoa~Wd!>V{~HmC5iS}7?2{XU6^2O;a7!zyt5AmGw0ejl*3JBL)y4MWgwfKn z@V%=K9)#7e_Cfd>$A=FBji-GKzIE}zW3Z;tJ_r{geefVG;oAq{LU9isgssc=LD+Nk z;6d1|YafLCPY)i0HSzW_*o*YwL0I{1AB25D4<3Y-&h|mbrSsr1Sl4SGgIzNZ9pnyv GjQ;^tWZ6sr literal 0 HcmV?d00001 diff --git a/public/js/discover~hashtag.bundle.76807a8ff71bd205.js b/public/js/discover~hashtag.bundle.76807a8ff71bd205.js deleted file mode 100644 index cd23b20451e8905205931cd3142548a5b69e81a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51774 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 abT$t{E}ch@!Ma}a80?yP>>&5>WBd<0MlBZr diff --git a/public/js/manifest.js b/public/js/manifest.js index a91c64b9de524a5d5f4c5ff79e7782940229ea9d..e8f53e3567a77e3b879ac3b33930a01f74476ce6 100644 GIT binary patch delta 29 kcmdm`xJz+E61#wrxn;7kiJ5_+sbz|BVw(BpB6bf>0ESoyV*mgE delta 29 kcmdm`xJz+E61#x8nT3IQqD5MoxnWX@k%8&vB6bf>0E$8glK=n! diff --git a/public/js/spa.js b/public/js/spa.js index 9cc2b3aa34fcefde6dcf70eab618fd4958866286..83593e77477b91ceab30144ba6a5d38792ac9f0e 100644 GIT binary patch delta 5584 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 delta 14387 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 TI%iu}uua*)L@=1f&+X3(5a~GC delta 204 zcmZ9GF$%&!5CE|Wf{H0b3yb)Iu({mcZV>SYf-jJ}y1LRvqP%CDH(X$OWG z>#=_Ci-QUfwVVxONZH9mlAzfD9CeO{WAT|)4lH1Y(acE)pe`^4)Yh{ofezdGZC+Af zpvY#_OeMhny4>`ya!voDemu|jd`e2FK*1WH9kMin+{82unTKfY@GVzG1x~z?7iEA% R$vj5R9DQa Date: Tue, 9 May 2023 04:05:54 -0600 Subject: [PATCH 16/16] Update changelog --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 033727ba0..9031fca7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.6...dev) +### API Changes +- Added [/api/v1/followed_tags](https://docs.joinmastodon.org/methods/followed_tags/) api endpoint ([175a8486](https://github.com/pixelfed/pixelfed/commit/175a8486)) +- Added [/api/v1/tags/:id/follow](https://docs.joinmastodon.org/methods/tags/#follow) and [/api/v1/tags/:id/unfollow](https://docs.joinmastodon.org/methods/tags/#unfollow) api endpoints ([4d997bb9](https://github.com/pixelfed/pixelfed/commit/4d997bb9)) +- Added [/api/v1/tags/:id](https://docs.joinmastodon.org/methods/tags/) api endpoint ([521b3b4c](https://github.com/pixelfed/pixelfed/commit/521b3b4c)) +- Added `only_media` support to /api/v1/timelines/tag/:id api endpoint ([b5fe956a](https://github.com/pixelfed/pixelfed/commit/b5fe956a)) + ### Added - Added store remote media on S3 config setting, disabled by default ([51768083](https://github.com/pixelfed/pixelfed/commit/51768083)) @@ -14,6 +20,14 @@ - Update instance config, enable config cache by default ([970f77b0](https://github.com/pixelfed/pixelfed/commit/970f77b0)) - Update Admin Dashboard, allow admins to designate an admin account for the landing page and instance api endpoint ([6ea2bdc7](https://github.com/pixelfed/pixelfed/commit/6ea2bdc7)) - Update config, enable oauth by default ([6a2e9e8f](https://github.com/pixelfed/pixelfed/commit/6a2e9e8f)) +- Update StatusService, fix missing account condition ([f48daab3](https://github.com/pixelfed/pixelfed/commit/f48daab3)) +- Update ProfileService, add softFail param ([6bc20a37](https://github.com/pixelfed/pixelfed/commit/6bc20a37)) +- Update MediaTagService, fix ProfileService to soft fail on missing or deleted accounts ([df444851](https://github.com/pixelfed/pixelfed/commit/df444851)) +- Update LikeService, improve likedBy logic to soft fail on missing or deleted accounts ([91ba1398](https://github.com/pixelfed/pixelfed/commit/91ba1398)) +- Update StatusTransformers, fix ProfileService to soft fail on missing or deleted accounts ([43d3aa2b](https://github.com/pixelfed/pixelfed/commit/43d3aa2b)) +- Update ApiV1Controller, fix hashtag timeline ([fc1a385c](https://github.com/pixelfed/pixelfed/commit/fc1a385c)) +- Update settings view, add fallback avatar ([1a83c585](https://github.com/pixelfed/pixelfed/commit/1a83c585)) +- Update HashtagFollow model, add MAX_LIMIT of 250 tags per account ([ed352141](https://github.com/pixelfed/pixelfed/commit/ed352141)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.6 (2023-05-03)](https://github.com/pixelfed/pixelfed/compare/v0.11.5...v0.11.6)