diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 11ab3a01b..b35ce35ff 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -2935,24 +2935,20 @@ class ApiV1Controller extends Controller $dir = $min_id ? '>' : '<'; $id = $min_id ?? $max_id; - if($id) { - $bookmarks = Bookmark::whereProfileId($pid) - ->where('status_id', $dir, $id) - ->limit($limit) - ->pluck('status_id'); - } else { - $bookmarks = Bookmark::whereProfileId($pid) - ->latest() - ->limit($limit) - ->pluck('status_id'); - } + $bookmarks = Bookmark::whereProfileId($pid) + ->when($id, function($id, $query) use($dir) { + return $query->where('status_id', $dir, $id); + }) + ->limit($limit) + ->pluck('status_id') + ->map(function($id) { + return \App\Services\StatusService::getMastodon($id); + }) + ->filter() + ->values() + ->toArray(); - $res = []; - foreach($bookmarks as $id) { - $res[] = \App\Services\StatusService::getMastodon($id); - } - - return $this->json($res); + return $this->json($bookmarks); } /** diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index b46fd38cd..43364312b 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -11,9 +11,11 @@ use League\Fractal\Serializer\ArraySerializer; use League\Fractal\Pagination\IlluminatePaginatorAdapter; use App\AccountLog; use App\EmailVerification; +use App\Place; use App\Status; use App\Report; use App\Profile; +use App\StatusArchived; use App\User; use App\Services\AccountService; use App\Services\StatusService; @@ -26,6 +28,7 @@ use Jenssegers\Agent\Agent; use Mail; use App\Mail\PasswordChange; use App\Mail\ConfirmAppEmail; +use App\Http\Resources\StatusStateless; class ApiV1Dot1Controller extends Controller { @@ -563,4 +566,103 @@ class ApiV1Dot1Controller extends Controller 'access_token' => $token->accessToken ]); } + + public function archive(Request $request, $id) + { + abort_if(!$request->user(), 403); + + $status = Status::whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereProfileId($request->user()->profile_id) + ->findOrFail($id); + + if($status->scope === 'archived') { + return [200]; + } + + $archive = new StatusArchived; + $archive->status_id = $status->id; + $archive->profile_id = $status->profile_id; + $archive->original_scope = $status->scope; + $archive->save(); + + $status->scope = 'archived'; + $status->visibility = 'draft'; + $status->save(); + StatusService::del($status->id, true); + AccountService::syncPostCount($status->profile_id); + + return [200]; + } + + + public function unarchive(Request $request, $id) + { + abort_if(!$request->user(), 403); + + $status = Status::whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereProfileId($request->user()->profile_id) + ->findOrFail($id); + + if($status->scope !== 'archived') { + return [200]; + } + + $archive = StatusArchived::whereStatusId($status->id) + ->whereProfileId($status->profile_id) + ->firstOrFail(); + + $status->scope = $archive->original_scope; + $status->visibility = $archive->original_scope; + $status->save(); + $archive->delete(); + StatusService::del($status->id, true); + AccountService::syncPostCount($status->profile_id); + + return [200]; + } + + public function archivedPosts(Request $request) + { + abort_if(!$request->user(), 403); + + $statuses = Status::whereProfileId($request->user()->profile_id) + ->whereScope('archived') + ->orderByDesc('id') + ->cursorPaginate(10); + + return StatusStateless::collection($statuses); + } + + public function placesById(Request $request, $id, $slug) + { + abort_if(!$request->user(), 403); + + $place = Place::whereSlug($slug)->findOrFail($id); + + $posts = Cache::remember('pf-api:v1.1:places-by-id:' . $place->id, 3600, function() use($place) { + return Status::wherePlaceId($place->id) + ->whereNull('uri') + ->whereScope('public') + ->orderByDesc('created_at') + ->limit(60) + ->pluck('id'); + }); + + $posts = $posts->map(function($id) { + return StatusService::get($id); + }) + ->filter() + ->values(); + + return ['place' => [ + 'id' => $place->id, + 'name' => $place->name, + 'slug' => $place->slug, + 'country' => $place->country, + 'lat' => $place->lat, + 'long' => $place->long + ], 'posts' => $posts]; + } } diff --git a/app/Http/Controllers/PlaceController.php b/app/Http/Controllers/PlaceController.php index 8bbf456b0..6b7760fdc 100644 --- a/app/Http/Controllers/PlaceController.php +++ b/app/Http/Controllers/PlaceController.php @@ -17,6 +17,10 @@ class PlaceController extends Controller public function show(Request $request, $id, $slug) { + $this->validate($request, [ + 'page' => 'sometimes|max:10' + ]); + $place = Place::whereSlug($slug)->findOrFail($id); $posts = Status::wherePlaceId($place->id) ->whereNull('uri') diff --git a/app/Http/Resources/StatusStateless.php b/app/Http/Resources/StatusStateless.php new file mode 100644 index 000000000..df451cc53 --- /dev/null +++ b/app/Http/Resources/StatusStateless.php @@ -0,0 +1,76 @@ +id); + $poll = $status->type === 'poll' ? PollService::get($status->id) : null; + + return [ + '_v' => 1, + 'id' => (string) $status->id, + //'gid' => $status->group_id ? (string) $status->group_id : null, + 'shortcode' => HashidService::encode($status->id), + 'uri' => $status->url(), + 'url' => $status->url(), + 'in_reply_to_id' => $status->in_reply_to_id ? (string) $status->in_reply_to_id : null, + 'in_reply_to_account_id' => $status->in_reply_to_profile_id ? (string) $status->in_reply_to_profile_id : null, + 'reblog' => null, + 'content' => $status->rendered ?? $status->caption, + 'content_text' => $status->caption, + 'created_at' => str_replace('+00:00', 'Z', $status->created_at->format(DATE_RFC3339_EXTENDED)), + 'emojis' => CustomEmoji::scan($status->caption), + 'reblogs_count' => $status->reblogs_count ?? 0, + 'favourites_count' => $status->likes_count ?? 0, + 'reblogged' => null, + 'favourited' => null, + 'muted' => null, + 'sensitive' => (bool) $status->is_nsfw, + 'spoiler_text' => $status->cw_summary ?? '', + 'visibility' => $status->scope ?? $status->visibility, + 'application' => [ + 'name' => 'web', + 'website' => null + ], + 'language' => null, + 'mentions' => StatusMentionService::get($status->id), + 'pf_type' => $status->type ?? $status->setType(), + 'reply_count' => (int) $status->reply_count, + 'comments_disabled' => (bool) $status->comments_disabled, + 'thread' => false, + 'replies' => [], + 'parent' => [], + 'place' => $status->place, + 'local' => (bool) $status->local, + 'taggedPeople' => $taggedPeople, + 'liked_by' => LikeService::likedBy($status), + 'media_attachments' => MediaService::get($status->id), + 'account' => AccountService::get($status->profile_id, true), + 'tags' => StatusHashtagService::statusTags($status->id), + 'poll' => $poll + ]; + } +} diff --git a/routes/api.php b/routes/api.php index 72fbf53c1..652440de3 100644 --- a/routes/api.php +++ b/routes/api.php @@ -131,6 +131,16 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::post('lookup', 'DirectMessageController@composeLookup')->middleware($middleware); }); + Route::group(['prefix' => 'archive'], function () use($middleware) { + Route::post('add/{id}', 'Api\ApiV1Dot1Controller@archive')->middleware($middleware); + Route::post('remove/{id}', 'Api\ApiV1Dot1Controller@unarchive')->middleware($middleware); + Route::get('list', 'Api\ApiV1Dot1Controller@archivedPosts')->middleware($middleware); + }); + + Route::group(['prefix' => 'places'], function () use($middleware) { + Route::get('posts/{id}/{slug}', 'Api\ApiV1Dot1Controller@placesById')->middleware($middleware); + }); + Route::group(['prefix' => 'stories'], function () use($middleware) { Route::get('recent', 'StoryController@recent')->middleware($middleware); });