|
|
|
@ -667,10 +667,8 @@ class PublicApiController extends Controller
|
|
|
|
|
'only_media' => 'nullable',
|
|
|
|
|
'pinned' => 'nullable',
|
|
|
|
|
'exclude_replies' => 'nullable',
|
|
|
|
|
'max_id' => 'nullable|integer|min:0|max:'.PHP_INT_MAX,
|
|
|
|
|
'since_id' => 'nullable|integer|min:0|max:'.PHP_INT_MAX,
|
|
|
|
|
'min_id' => 'nullable|integer|min:0|max:'.PHP_INT_MAX,
|
|
|
|
|
'limit' => 'nullable|integer|min:1|max:24',
|
|
|
|
|
'cursor' => 'nullable',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$user = $request->user();
|
|
|
|
@ -683,84 +681,137 @@ class PublicApiController extends Controller
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$limit = $request->limit ?? 9;
|
|
|
|
|
$max_id = $request->max_id;
|
|
|
|
|
$min_id = $request->min_id;
|
|
|
|
|
$scope = ['photo', 'photo:album', 'video', 'video:album'];
|
|
|
|
|
$onlyMedia = $request->input('only_media', true);
|
|
|
|
|
$pinned = $request->filled('pinned') && $request->boolean('pinned') == true;
|
|
|
|
|
$hasCursor = $request->filled('cursor');
|
|
|
|
|
|
|
|
|
|
$visibility = $this->determineVisibility($profile, $user);
|
|
|
|
|
|
|
|
|
|
if (empty($visibility)) {
|
|
|
|
|
return response()->json([]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result = collect();
|
|
|
|
|
$remainingLimit = $limit;
|
|
|
|
|
|
|
|
|
|
if (! $min_id && ! $max_id) {
|
|
|
|
|
$min_id = 1;
|
|
|
|
|
if ($pinned && ! $hasCursor) {
|
|
|
|
|
$pinnedStatuses = Status::whereProfileId($profile['id'])
|
|
|
|
|
->whereNotNull('pinned_order')
|
|
|
|
|
->orderBy('pinned_order')
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
$pinnedResult = $this->processStatuses($pinnedStatuses, $user, $onlyMedia);
|
|
|
|
|
$result = $pinnedResult;
|
|
|
|
|
|
|
|
|
|
$remainingLimit = max(1, $limit - $pinnedResult->count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$paginator = Status::whereProfileId($profile['id'])
|
|
|
|
|
->whereNull('in_reply_to_id')
|
|
|
|
|
->whereNull('reblog_of_id')
|
|
|
|
|
->when($pinned, function ($query) {
|
|
|
|
|
return $query->whereNull('pinned_order');
|
|
|
|
|
})
|
|
|
|
|
->whereIn('type', $scope)
|
|
|
|
|
->whereIn('scope', $visibility)
|
|
|
|
|
->orderByDesc('id')
|
|
|
|
|
->cursorPaginate($remainingLimit)
|
|
|
|
|
->withQueryString();
|
|
|
|
|
|
|
|
|
|
$headers = $this->generatePaginationHeaders($paginator);
|
|
|
|
|
$regularStatuses = $this->processStatuses($paginator->items(), $user, $onlyMedia);
|
|
|
|
|
$result = $result->concat($regularStatuses);
|
|
|
|
|
|
|
|
|
|
return response()->json($result, 200, $headers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function determineVisibility($profile, $user)
|
|
|
|
|
{
|
|
|
|
|
if ($profile['id'] == $user->profile_id) {
|
|
|
|
|
return ['public', 'unlisted', 'private'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($profile['locked']) {
|
|
|
|
|
if (! $user) {
|
|
|
|
|
return response()->json([]);
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$pid = $user->profile_id;
|
|
|
|
|
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function () use ($pid) {
|
|
|
|
|
$following = Follower::whereProfileId($pid)->pluck('following_id');
|
|
|
|
|
$isFollowing = Follower::whereProfileId($pid)
|
|
|
|
|
->whereFollowingId($profile['id'])
|
|
|
|
|
->exists();
|
|
|
|
|
|
|
|
|
|
return $following->push($pid)->toArray();
|
|
|
|
|
});
|
|
|
|
|
$visibility = in_array($profile['id'], $following) == true ? ['public', 'unlisted', 'private'] : [];
|
|
|
|
|
return $isFollowing ? ['public', 'unlisted', 'private'] : ['public'];
|
|
|
|
|
} else {
|
|
|
|
|
if ($user) {
|
|
|
|
|
$pid = $user->profile_id;
|
|
|
|
|
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function () use ($pid) {
|
|
|
|
|
$following = Follower::whereProfileId($pid)->pluck('following_id');
|
|
|
|
|
$isFollowing = Follower::whereProfileId($pid)
|
|
|
|
|
->whereFollowingId($profile['id'])
|
|
|
|
|
->exists();
|
|
|
|
|
|
|
|
|
|
return $following->push($pid)->toArray();
|
|
|
|
|
});
|
|
|
|
|
$visibility = in_array($profile['id'], $following) == true ? ['public', 'unlisted', 'private'] : ['public', 'unlisted'];
|
|
|
|
|
return $isFollowing ? ['public', 'unlisted', 'private'] : ['public', 'unlisted'];
|
|
|
|
|
} else {
|
|
|
|
|
$visibility = ['public', 'unlisted'];
|
|
|
|
|
return ['public', 'unlisted'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$dir = $min_id ? '>' : '<';
|
|
|
|
|
$id = $min_id ?? $max_id;
|
|
|
|
|
$res = Status::whereProfileId($profile['id'])
|
|
|
|
|
->whereNull('in_reply_to_id')
|
|
|
|
|
->whereNull('reblog_of_id')
|
|
|
|
|
->whereIn('type', $scope)
|
|
|
|
|
->where('id', $dir, $id)
|
|
|
|
|
->whereIn('scope', $visibility)
|
|
|
|
|
->limit($limit)
|
|
|
|
|
->orderBy('pinned_order')
|
|
|
|
|
->orderByDesc('id')
|
|
|
|
|
->get()
|
|
|
|
|
->map(function ($s) use ($user) {
|
|
|
|
|
try {
|
|
|
|
|
$status = StatusService::get($s->id, false);
|
|
|
|
|
if (! $status) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$status = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function processStatuses($statuses, $user, $onlyMedia)
|
|
|
|
|
{
|
|
|
|
|
return collect($statuses)->map(function ($status) use ($user) {
|
|
|
|
|
try {
|
|
|
|
|
$mastodonStatus = StatusService::getMastodon($status->id, false);
|
|
|
|
|
if (! $mastodonStatus) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if ($user && $status) {
|
|
|
|
|
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
|
|
|
|
|
|
|
|
|
if ($user) {
|
|
|
|
|
$mastodonStatus['favourited'] = (bool) LikeService::liked($user->profile_id, $status->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
})
|
|
|
|
|
->filter(function ($s) use ($onlyMedia) {
|
|
|
|
|
if (! $s) {
|
|
|
|
|
return $mastodonStatus;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
->filter(function ($status) use ($onlyMedia) {
|
|
|
|
|
if (! $status) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($onlyMedia) {
|
|
|
|
|
if (
|
|
|
|
|
! isset($s['media_attachments']) ||
|
|
|
|
|
! is_array($s['media_attachments']) ||
|
|
|
|
|
empty($s['media_attachments'])
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return isset($status['media_attachments']) &&
|
|
|
|
|
is_array($status['media_attachments']) &&
|
|
|
|
|
! empty($status['media_attachments']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $s;
|
|
|
|
|
return true;
|
|
|
|
|
})
|
|
|
|
|
->values();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response()->json($res);
|
|
|
|
|
/**
|
|
|
|
|
* Generate pagination link headers from paginator
|
|
|
|
|
*/
|
|
|
|
|
private function generatePaginationHeaders($paginator)
|
|
|
|
|
{
|
|
|
|
|
$link = null;
|
|
|
|
|
|
|
|
|
|
if ($paginator->onFirstPage()) {
|
|
|
|
|
if ($paginator->hasMorePages()) {
|
|
|
|
|
$link = '<'.$paginator->nextPageUrl().'>; rel="prev"';
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ($paginator->previousPageUrl()) {
|
|
|
|
|
$link = '<'.$paginator->previousPageUrl().'>; rel="next"';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($paginator->hasMorePages()) {
|
|
|
|
|
$link .= ($link ? ', ' : '').'<'.$paginator->nextPageUrl().'>; rel="prev"';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isset($link) ? ['Link' => $link] : [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|