mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-26 00:03:16 +00:00
Update ApiV1Controller, improve settings and add discoverPosts endpoint
This commit is contained in:
parent
cdaa153003
commit
079804e65b
1 changed files with 441 additions and 96 deletions
|
@ -10,7 +10,9 @@ use App\Util\Media\Filter;
|
|||
use Laravel\Passport\Passport;
|
||||
use Auth, Cache, DB, URL;
|
||||
use App\{
|
||||
Avatar,
|
||||
Bookmark,
|
||||
DirectMessage,
|
||||
Follower,
|
||||
FollowRequest,
|
||||
Hashtag,
|
||||
|
@ -38,6 +40,8 @@ use App\Http\Controllers\FollowerController;
|
|||
use League\Fractal\Serializer\ArraySerializer;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use App\Http\Controllers\StatusController;
|
||||
|
||||
use App\Jobs\AvatarPipeline\AvatarOptimize;
|
||||
use App\Jobs\LikePipeline\LikePipeline;
|
||||
use App\Jobs\SharePipeline\SharePipeline;
|
||||
use App\Jobs\StatusPipeline\NewStatusPipeline;
|
||||
|
@ -49,8 +53,11 @@ use App\Jobs\VideoPipeline\{
|
|||
VideoPostProcess,
|
||||
VideoThumbnail
|
||||
};
|
||||
|
||||
use App\Services\{
|
||||
AccountService,
|
||||
LikeService,
|
||||
InstanceService,
|
||||
NotificationService,
|
||||
MediaPathService,
|
||||
PublicTimelineService,
|
||||
|
@ -59,9 +66,13 @@ use App\Services\{
|
|||
SearchApiV2Service,
|
||||
StatusService,
|
||||
MediaBlocklistService,
|
||||
SnowflakeService,
|
||||
UserFilterService
|
||||
};
|
||||
use App\Util\Lexer\Autolink;
|
||||
use App\Util\Localization\Localization;
|
||||
use App\Util\Media\License;
|
||||
use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
|
||||
|
||||
class ApiV1Controller extends Controller
|
||||
{
|
||||
|
@ -166,47 +177,222 @@ class ApiV1Controller extends Controller
|
|||
abort_if(!$request->user(), 403);
|
||||
|
||||
$this->validate($request, [
|
||||
'avatar' => 'sometimes|mimetypes:image/jpeg,image/png',
|
||||
'display_name' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'locked' => 'nullable',
|
||||
'website' => 'nullable',
|
||||
// 'source.privacy' => 'nullable|in:unlisted,public,private',
|
||||
// 'source.sensitive' => 'nullable|boolean'
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
$profile = $user->profile;
|
||||
|
||||
$displayName = $request->input('display_name');
|
||||
$note = $request->input('note');
|
||||
$locked = $request->input('locked');
|
||||
// $privacy = $request->input('source.privacy');
|
||||
// $sensitive = $request->input('source.sensitive');
|
||||
$settings = $user->settings;
|
||||
|
||||
$changes = false;
|
||||
$other = array_merge(AccountService::defaultSettings()['other'], $settings->other ?? []);
|
||||
$syncLicenses = false;
|
||||
$licenseChanged = false;
|
||||
$composeSettings = array_merge(AccountService::defaultSettings()['compose_settings'], $settings->compose_settings ?? []);
|
||||
|
||||
// return $request->input('locked');
|
||||
|
||||
if($request->has('avatar')) {
|
||||
$av = Avatar::whereProfileId($profile->id)->first();
|
||||
if($av) {
|
||||
$currentAvatar = storage_path('app/'.$av->media_path);
|
||||
$file = $request->file('avatar');
|
||||
$path = "public/avatars/{$profile->id}";
|
||||
$name = strtolower(str_random(6)). '.' . $file->guessExtension();
|
||||
$request->file('avatar')->storeAs($path, $name);
|
||||
$av->media_path = "{$path}/{$name}";
|
||||
$av->save();
|
||||
Cache::forget("avatar:{$profile->id}");
|
||||
Cache::forget('user:account:id:'.$user->id);
|
||||
AvatarOptimize::dispatch($user->profile, $currentAvatar);
|
||||
}
|
||||
$changes = true;
|
||||
}
|
||||
|
||||
if($request->has('source[language]')) {
|
||||
$lang = $request->input('source[language]');
|
||||
if(in_array($lang, Localization::languages())) {
|
||||
$user->language = $lang;
|
||||
$changes = true;
|
||||
$other['language'] = $lang;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('website')) {
|
||||
$website = $request->input('website');
|
||||
if($website != $profile->website) {
|
||||
if($website) {
|
||||
if(!strpos($website, '.')) {
|
||||
$website = null;
|
||||
}
|
||||
|
||||
if($website && !strpos($website, '://')) {
|
||||
$website = 'https://' . $website;
|
||||
}
|
||||
|
||||
$host = parse_url($website, PHP_URL_HOST);
|
||||
|
||||
$bannedInstances = InstanceService::getBannedDomains();
|
||||
if(in_array($host, $bannedInstances)) {
|
||||
$website = null;
|
||||
}
|
||||
}
|
||||
$profile->website = $website ? $website : null;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('display_name')) {
|
||||
$displayName = $request->input('display_name');
|
||||
if($displayName !== $user->name) {
|
||||
$user->name = $displayName;
|
||||
$profile->name = $displayName;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('note')) {
|
||||
$note = $request->input('note');
|
||||
if($note !== strip_tags($profile->bio)) {
|
||||
$profile->bio = Autolink::create()->autolink(strip_tags($note));
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_null($locked)) {
|
||||
if($request->has('locked')) {
|
||||
$locked = $request->input('locked') == 'true';
|
||||
if($profile->is_private != $locked) {
|
||||
$profile->is_private = $locked;
|
||||
$changes = true;
|
||||
}
|
||||
|
||||
if($changes) {
|
||||
$user->save();
|
||||
$profile->save();
|
||||
}
|
||||
|
||||
$resource = new Fractal\Resource\Item($profile, new AccountTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
if($request->has('reduce_motion')) {
|
||||
$reduced = $request->input('reduce_motion');
|
||||
if($settings->reduce_motion != $reduced) {
|
||||
$settings->reduce_motion = $reduced;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('high_contrast_mode')) {
|
||||
$contrast = $request->input('high_contrast_mode');
|
||||
if($settings->high_contrast_mode != $contrast) {
|
||||
$settings->high_contrast_mode = $contrast;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('video_autoplay')) {
|
||||
$autoplay = $request->input('video_autoplay');
|
||||
if($settings->video_autoplay != $autoplay) {
|
||||
$settings->video_autoplay = $autoplay;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('license')) {
|
||||
$license = $request->input('license');
|
||||
abort_if(!in_array($license, License::keys()), 422, 'Invalid media license id');
|
||||
$syncLicenses = $request->input('sync_licenses') == true;
|
||||
abort_if($syncLicenses && Cache::get('pf:settings:mls_recently:'.$user->id) == 2, 422, 'You can only sync licenses twice per 24 hours');
|
||||
if($composeSettings['default_license'] != $license) {
|
||||
$composeSettings['default_license'] = $license;
|
||||
$licenseChanged = true;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('media_descriptions')) {
|
||||
$md = $request->input('media_descriptions') == true;
|
||||
if($composeSettings['media_descriptions'] != $md) {
|
||||
$composeSettings['media_descriptions'] = $md;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('crawlable')) {
|
||||
$crawlable = $request->input('crawlable');
|
||||
if($settings->crawlable != $crawlable) {
|
||||
$settings->crawlable = $crawlable;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('show_profile_follower_count')) {
|
||||
$show_profile_follower_count = $request->input('show_profile_follower_count');
|
||||
if($settings->show_profile_follower_count != $show_profile_follower_count) {
|
||||
$settings->show_profile_follower_count = $show_profile_follower_count;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('show_profile_following_count')) {
|
||||
$show_profile_following_count = $request->input('show_profile_following_count');
|
||||
if($settings->show_profile_following_count != $show_profile_following_count) {
|
||||
$settings->show_profile_following_count = $show_profile_following_count;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('public_dm')) {
|
||||
$public_dm = $request->input('public_dm');
|
||||
if($settings->public_dm != $public_dm) {
|
||||
$settings->public_dm = $public_dm;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('source[privacy]')) {
|
||||
$scope = $request->input('source[privacy]');
|
||||
if(in_array($scope, ['public', 'private', 'unlisted'])) {
|
||||
if($composeSettings['default_scope'] != $scope) {
|
||||
$composeSettings['default_scope'] = $profile->is_private ? 'private' : $scope;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($request->has('disable_embeds')) {
|
||||
$disabledEmbeds = $request->input('disable_embeds');
|
||||
if($other['disable_embeds'] != $disabledEmbeds) {
|
||||
$other['disable_embeds'] = $disabledEmbeds;
|
||||
$changes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changes) {
|
||||
$settings->other = $other;
|
||||
$settings->compose_settings = $composeSettings;
|
||||
$settings->save();
|
||||
$user->save();
|
||||
$profile->save();
|
||||
Cache::forget('profile:settings:' . $profile->id);
|
||||
Cache::forget('user:account:id:' . $profile->user_id);
|
||||
Cache::forget('profile:follower_count:' . $profile->id);
|
||||
Cache::forget('profile:following_count:' . $profile->id);
|
||||
Cache::forget('profile:embed:' . $profile->id);
|
||||
Cache::forget('profile:compose:settings:' . $user->id);
|
||||
Cache::forget('profile:view:'.$user->username);
|
||||
AccountService::del($user->profile_id);
|
||||
}
|
||||
|
||||
if($syncLicenses && $licenseChanged) {
|
||||
$key = 'pf:settings:mls_recently:'.$user->id;
|
||||
$val = Cache::has($key) ? 2 : 1;
|
||||
Cache::put($key, $val, 86400);
|
||||
MediaSyncLicensePipeline::dispatch($user->id, $request->input('license'));
|
||||
}
|
||||
|
||||
$res = AccountService::get($user->profile_id);
|
||||
$res['bio'] = strip_tags($res['note']);
|
||||
$res = array_merge($res, $other);
|
||||
|
||||
return response()->json($res);
|
||||
}
|
||||
|
@ -305,9 +491,11 @@ class ApiV1Controller extends Controller
|
|||
public function accountStatusesById(Request $request, $id)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
$user = $request->user();
|
||||
|
||||
$this->validate($request, [
|
||||
'only_media' => 'nullable',
|
||||
'media_type' => 'sometimes|string|in:photo,video',
|
||||
'pinned' => 'nullable',
|
||||
'exclude_replies' => 'nullable',
|
||||
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||
|
@ -316,7 +504,8 @@ class ApiV1Controller extends Controller
|
|||
'limit' => 'nullable|integer|min:1|max:80'
|
||||
]);
|
||||
|
||||
$profile = Profile::whereNull('status')->findOrFail($id);
|
||||
$profile = AccountService::get($id);
|
||||
abort_if(!$profile, 404);
|
||||
|
||||
$limit = $request->limit ?? 20;
|
||||
$max_id = $request->max_id;
|
||||
|
@ -326,77 +515,56 @@ class ApiV1Controller extends Controller
|
|||
['photo', 'photo:album', 'video', 'video:album'] :
|
||||
['photo', 'photo:album', 'video', 'video:album', 'share', 'reply'];
|
||||
|
||||
if($pid == $profile->id) {
|
||||
if($request->only_media && $request->has('media_type')) {
|
||||
$mt = $request->input('media_type');
|
||||
if($mt == 'video') {
|
||||
$scope = ['video', 'video:album'];
|
||||
}
|
||||
}
|
||||
|
||||
if($pid == $profile['id']) {
|
||||
$visibility = ['public', 'unlisted', 'private'];
|
||||
} else if($profile->is_private) {
|
||||
} else if($profile['locked']) {
|
||||
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function() use($pid) {
|
||||
$following = Follower::whereProfileId($pid)->pluck('following_id');
|
||||
return $following->push($pid)->toArray();
|
||||
});
|
||||
$visibility = true == in_array($profile->id, $following) ? ['public', 'unlisted', 'private'] : [];
|
||||
$visibility = true == in_array($profile['id'], $following) ? ['public', 'unlisted', 'private'] : [];
|
||||
} else {
|
||||
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function() use($pid) {
|
||||
$following = Follower::whereProfileId($pid)->pluck('following_id');
|
||||
return $following->push($pid)->toArray();
|
||||
});
|
||||
$visibility = true == in_array($profile->id, $following) ? ['public', 'unlisted', 'private'] : ['public', 'unlisted'];
|
||||
$visibility = true == in_array($profile['id'], $following) ? ['public', 'unlisted', 'private'] : ['public', 'unlisted'];
|
||||
}
|
||||
|
||||
if($min_id || $max_id) {
|
||||
$dir = $min_id ? '>' : '<';
|
||||
$id = $min_id ?? $max_id;
|
||||
$timeline = Status::select(
|
||||
'id',
|
||||
'uri',
|
||||
'caption',
|
||||
'rendered',
|
||||
'profile_id',
|
||||
'type',
|
||||
'in_reply_to_id',
|
||||
'reblog_of_id',
|
||||
'is_nsfw',
|
||||
'scope',
|
||||
'local',
|
||||
'place_id',
|
||||
'likes_count',
|
||||
'reblogs_count',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
)->whereProfileId($profile->id)
|
||||
$res = Status::whereProfileId($profile['id'])
|
||||
->whereNull('in_reply_to_id')
|
||||
->whereNull('reblog_of_id')
|
||||
->whereIn('type', $scope)
|
||||
->where('id', $dir, $id)
|
||||
->whereIn('visibility', $visibility)
|
||||
->latest()
|
||||
->whereIn('scope', $visibility)
|
||||
->limit($limit)
|
||||
->get();
|
||||
} else {
|
||||
$timeline = Status::select(
|
||||
'id',
|
||||
'uri',
|
||||
'caption',
|
||||
'rendered',
|
||||
'profile_id',
|
||||
'type',
|
||||
'in_reply_to_id',
|
||||
'reblog_of_id',
|
||||
'is_nsfw',
|
||||
'scope',
|
||||
'local',
|
||||
'place_id',
|
||||
'likes_count',
|
||||
'reblogs_count',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
)->whereProfileId($profile->id)
|
||||
->whereIn('type', $scope)
|
||||
->whereIn('visibility', $visibility)
|
||||
->latest()
|
||||
->limit($limit)
|
||||
->get();
|
||||
->orderByDesc('id')
|
||||
->get()
|
||||
->map(function($s) use($user) {
|
||||
try {
|
||||
$status = StatusService::get($s->id, false);
|
||||
} catch (\Exception $e) {
|
||||
$status = false;
|
||||
}
|
||||
if($user && $status) {
|
||||
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $s->id);
|
||||
}
|
||||
return $status;
|
||||
})
|
||||
->filter(function($s) {
|
||||
return $s;
|
||||
})
|
||||
->values();
|
||||
|
||||
$resource = new Fractal\Resource\Collection($timeline, new StatusTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
|
@ -417,6 +585,7 @@ class ApiV1Controller extends Controller
|
|||
->whereNull('status')
|
||||
->findOrFail($id);
|
||||
|
||||
|
||||
$private = (bool) $target->is_private;
|
||||
$remote = (bool) $target->domain;
|
||||
$blocked = UserFilter::whereUserId($target->id)
|
||||
|
@ -435,9 +604,7 @@ class ApiV1Controller extends Controller
|
|||
|
||||
// Following already, return empty relationship
|
||||
if($isFollowing == true) {
|
||||
$resource = new Fractal\Resource\Item($target, new RelationshipTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
|
||||
$res = RelationshipService::get($user->profile_id, $target->id) ?? [];
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
|
@ -471,6 +638,7 @@ class ApiV1Controller extends Controller
|
|||
FollowPipeline::dispatch($follower);
|
||||
}
|
||||
|
||||
RelationshipService::refresh($user->profile_id, $target->id);
|
||||
Cache::forget('profile:following:'.$target->id);
|
||||
Cache::forget('profile:followers:'.$target->id);
|
||||
Cache::forget('profile:following:'.$user->profile_id);
|
||||
|
@ -483,8 +651,7 @@ class ApiV1Controller extends Controller
|
|||
Cache::forget('profile:following_count:'.$target->id);
|
||||
Cache::forget('profile:following_count:'.$user->profile_id);
|
||||
|
||||
$resource = new Fractal\Resource\Item($target, new RelationshipTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
$res = RelationshipService::get($user->profile_id, $target->id);
|
||||
|
||||
return response()->json($res);
|
||||
}
|
||||
|
@ -506,6 +673,8 @@ class ApiV1Controller extends Controller
|
|||
->whereNull('status')
|
||||
->findOrFail($id);
|
||||
|
||||
RelationshipService::refresh($user->profile_id, $target->id);
|
||||
|
||||
$private = (bool) $target->is_private;
|
||||
$remote = (bool) $target->domain;
|
||||
|
||||
|
@ -770,20 +939,54 @@ class ApiV1Controller extends Controller
|
|||
public function accountFavourites(Request $request)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
$this->validate($request, [
|
||||
'limit' => 'sometimes|integer|min:1|max:20'
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
$maxId = $request->input('max_id');
|
||||
$minId = $request->input('min_id');
|
||||
$limit = $request->input('limit') ?? 10;
|
||||
|
||||
$limit = $request->input('limit') ?? 20;
|
||||
$favourites = Like::whereProfileId($user->profile_id)
|
||||
->latest()
|
||||
->simplePaginate($limit)
|
||||
->pluck('status_id');
|
||||
$res = Like::whereProfileId($user->profile_id)
|
||||
->when($maxId, function($q, $maxId) {
|
||||
return $q->where('id', '<', $maxId);
|
||||
})
|
||||
->when($minId, function($q, $minId) {
|
||||
return $q->where('id', '>', $minId);
|
||||
})
|
||||
->orderByDesc('id')
|
||||
->limit($limit)
|
||||
->get()
|
||||
->map(function($like) {
|
||||
$status = StatusService::get($like['status_id'], false);
|
||||
$status['like_id'] = $like->id;
|
||||
$status['liked_at'] = $like->created_at->format('c');
|
||||
return $status;
|
||||
})
|
||||
->filter(function($status) {
|
||||
return $status && isset($status['id'], $status['like_id']);
|
||||
})
|
||||
->values();
|
||||
|
||||
$statuses = Status::findOrFail($favourites);
|
||||
$resource = new Fractal\Resource\Collection($statuses, new StatusTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
if($res->count()) {
|
||||
$ids = $res->map(function($status) {
|
||||
return $status['like_id'];
|
||||
});
|
||||
$max = $ids->max();
|
||||
$min = $ids->min();
|
||||
|
||||
$baseUrl = config('app.url') . '/api/v1/favourites?limit=' . $limit . '&';
|
||||
$link = '<'.$baseUrl.'max_id='.$max.'>; rel="next",<'.$baseUrl.'min_id='.$min.'>; rel="prev"';
|
||||
return response()
|
||||
->json($res)
|
||||
->withHeaders([
|
||||
'Link' => $link,
|
||||
]);
|
||||
} else {
|
||||
return response()->json($res);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/statuses/{id}/favourite
|
||||
|
@ -1098,6 +1301,17 @@ class ApiV1Controller extends Controller
|
|||
$path = $photo->store($storagePath);
|
||||
$hash = \hash_file('sha256', $photo);
|
||||
$license = null;
|
||||
$mime = $photo->getMimeType();
|
||||
|
||||
// if($photo->getMimeType() == 'image/heic') {
|
||||
// abort_if(config('image.driver') !== 'imagick', 422, 'Invalid media type');
|
||||
// abort_if(!in_array('HEIC', \Imagick::queryformats()), 422, 'Unsupported media type');
|
||||
// $oldPath = $path;
|
||||
// $path = str_replace('.heic', '.jpg', $path);
|
||||
// $mime = 'image/jpeg';
|
||||
// \Image::make($photo)->save(storage_path("app/{$path}"));
|
||||
// @unlink(storage_path("app/{$oldPath}"));
|
||||
// }
|
||||
|
||||
$settings = UserSetting::whereUserId($user->id)->first();
|
||||
|
||||
|
@ -1118,7 +1332,7 @@ class ApiV1Controller extends Controller
|
|||
$media->media_path = $path;
|
||||
$media->original_sha256 = $hash;
|
||||
$media->size = $photo->getSize();
|
||||
$media->mime = $photo->getMimeType();
|
||||
$media->mime = $mime;
|
||||
$media->caption = $request->input('description');
|
||||
$media->filter_class = $filterClass;
|
||||
$media->filter_name = $filterName;
|
||||
|
@ -1327,7 +1541,7 @@ class ApiV1Controller extends Controller
|
|||
NotificationService::warmCache($pid, 400, true);
|
||||
}
|
||||
|
||||
$baseUrl = config('app.url') . '/api/v1/notifications?';
|
||||
$baseUrl = config('app.url') . '/api/v1/notifications?limit=' . $limit . '&';
|
||||
|
||||
if($minId == $maxId) {
|
||||
$minId = null;
|
||||
|
@ -1469,8 +1683,47 @@ class ApiV1Controller extends Controller
|
|||
public function conversations(Request $request)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
$this->validate($request, [
|
||||
'limit' => 'min:1|max:40',
|
||||
'scope' => 'nullable|in:inbox,sent,requests'
|
||||
]);
|
||||
|
||||
return response()->json([]);
|
||||
$limit = $request->input('limit', 20);
|
||||
$scope = $request->input('scope', 'inbox');
|
||||
$pid = $request->user()->profile_id;
|
||||
|
||||
$dms = DirectMessage::when($scope === 'inbox', function($q, $scope) use($pid) {
|
||||
return $q->whereIsHidden(false)->whereToId($pid)->orWhere('from_id', $pid)->groupBy('to_id');
|
||||
})
|
||||
->when($scope === 'sent', function($q, $scope) use($pid) {
|
||||
return $q->whereFromId($pid)->groupBy('to_id');
|
||||
})
|
||||
->when($scope === 'requests', function($q, $scope) use($pid) {
|
||||
return $q->whereToId($pid)->whereIsHidden(true);
|
||||
})
|
||||
->latest()
|
||||
->simplePaginate($limit)
|
||||
->map(function($dm) use($pid) {
|
||||
$from = $pid == $dm->to_id ? $dm->from_id : $dm->to_id;
|
||||
$res = [
|
||||
'id' => $dm->id,
|
||||
'unread' => false,
|
||||
'accounts' => [
|
||||
AccountService::get($from)
|
||||
],
|
||||
'last_status' => StatusService::getDirectMessage($dm->status_id)
|
||||
];
|
||||
return $res;
|
||||
})
|
||||
->filter(function($dm) {
|
||||
return isset($dm['accounts']) && count($dm['accounts']);
|
||||
})
|
||||
->unique(function($item, $key) {
|
||||
return $item['accounts'][0]['id'];
|
||||
})
|
||||
->values();
|
||||
|
||||
return response()->json($dms);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1688,9 +1941,16 @@ class ApiV1Controller extends Controller
|
|||
'limit' => 'nullable|integer|min:1|max:80'
|
||||
]);
|
||||
|
||||
$page = $request->input('page', 1);
|
||||
$limit = $request->input('limit') ?? 40;
|
||||
$user = $request->user();
|
||||
$status = Status::findOrFail($id);
|
||||
$offset = $page == 1 ? 0 : ($page * $limit - $limit);
|
||||
if($offset > 100) {
|
||||
if($user->profile_id != $status->profile_id) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if($status->profile_id !== $user->profile_id) {
|
||||
if($status->scope == 'private') {
|
||||
|
@ -1700,9 +1960,27 @@ class ApiV1Controller extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
$liked = $status->likedBy()->latest()->simplePaginate($limit);
|
||||
$resource = new Fractal\Resource\Collection($liked, new AccountTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
$res = DB::table('likes')
|
||||
->select('likes.id', 'likes.profile_id', 'likes.status_id', 'followers.created_at')
|
||||
->leftJoin('followers', function($join) use($user, $status) {
|
||||
return $join->on('likes.profile_id', '=', 'followers.following_id')
|
||||
->where('followers.profile_id', $user->profile_id)
|
||||
->where('likes.status_id', $status->id);
|
||||
})
|
||||
->whereStatusId($status->id)
|
||||
->orderByDesc('followers.created_at')
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
->get()
|
||||
->map(function($like) {
|
||||
$account = AccountService::get($like->profile_id);
|
||||
$account['follows'] = isset($like->created_at);
|
||||
return $account;
|
||||
})
|
||||
->filter(function($account) use($user) {
|
||||
return $account && isset($account['id']) && $account['id'] != $user->profile_id;
|
||||
})
|
||||
->values();
|
||||
|
||||
$url = $request->url();
|
||||
$page = $request->input('page', 1);
|
||||
|
@ -2131,4 +2409,71 @@ class ApiV1Controller extends Controller
|
|||
|
||||
return SearchApiV2Service::query($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/discover/posts
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function discoverPosts(Request $request)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
|
||||
$this->validate($request, [
|
||||
'limit' => 'integer|min:1|max:40'
|
||||
]);
|
||||
|
||||
$limit = $request->input('limit', 40);
|
||||
$profile = Auth::user()->profile;
|
||||
$pid = $profile->id;
|
||||
|
||||
$following = Cache::remember('feature:discover:following:'.$pid, now()->addMinutes(15), function() use ($pid) {
|
||||
return Follower::whereProfileId($pid)->pluck('following_id')->toArray();
|
||||
});
|
||||
|
||||
$filters = Cache::remember("user:filter:list:$pid", now()->addMinutes(15), function() use($pid) {
|
||||
$private = Profile::whereIsPrivate(true)
|
||||
->orWhere('unlisted', true)
|
||||
->orWhere('status', '!=', null)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
$filters = UserFilter::whereUserId($pid)
|
||||
->whereFilterableType('App\Profile')
|
||||
->whereIn('filter_type', ['mute', 'block'])
|
||||
->pluck('filterable_id')
|
||||
->toArray();
|
||||
return array_merge($private, $filters);
|
||||
});
|
||||
$following = array_merge($following, $filters);
|
||||
|
||||
$sql = config('database.default') !== 'pgsql';
|
||||
$min_id = SnowflakeService::byDate(now()->subMonths(3));
|
||||
$res = Status::select(
|
||||
'id',
|
||||
'is_nsfw',
|
||||
'profile_id',
|
||||
'type',
|
||||
'uri',
|
||||
)
|
||||
->whereNull('uri')
|
||||
->whereIn('type', ['photo','photo:album', 'video'])
|
||||
->whereIsNsfw(false)
|
||||
->whereVisibility('public')
|
||||
->whereNotIn('profile_id', $following)
|
||||
->where('id', '>', $min_id)
|
||||
->inRandomOrder()
|
||||
->take($limit)
|
||||
->pluck('id')
|
||||
->map(function($post) {
|
||||
return StatusService::get($post);
|
||||
})
|
||||
->filter(function($post) {
|
||||
return $post && isset($post['id']);
|
||||
})
|
||||
->values()
|
||||
->toArray();
|
||||
|
||||
return response()->json($res);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue