From ebbd98e743b317232300d4089ac1f9c53184da99 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 13 Dec 2023 06:30:05 -0700 Subject: [PATCH 1/3] Update AccountService, add setLastActive method --- app/Services/AccountService.php | 376 +++++++++++++++++--------------- 1 file changed, 195 insertions(+), 181 deletions(-) diff --git a/app/Services/AccountService.php b/app/Services/AccountService.php index ea64855ce..fa1613cae 100644 --- a/app/Services/AccountService.php +++ b/app/Services/AccountService.php @@ -15,209 +15,223 @@ use Illuminate\Support\Str; class AccountService { - const CACHE_KEY = 'pf:services:account:'; + const CACHE_KEY = 'pf:services:account:'; - public static function get($id, $softFail = false) - { - $res = Cache::remember(self::CACHE_KEY . $id, 43200, function() use($id) { - $fractal = new Fractal\Manager(); - $fractal->setSerializer(new ArraySerializer()); - $profile = Profile::find($id); - if(!$profile || $profile->status === 'delete') { - return null; - } - $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); - return $fractal->createData($resource)->toArray(); - }); + public static function get($id, $softFail = false) + { + $res = Cache::remember(self::CACHE_KEY . $id, 43200, function() use($id) { + $fractal = new Fractal\Manager(); + $fractal->setSerializer(new ArraySerializer()); + $profile = Profile::find($id); + if(!$profile || $profile->status === 'delete') { + return null; + } + $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); + return $fractal->createData($resource)->toArray(); + }); - if(!$res) { - return $softFail ? null : abort(404); - } - return $res; - } + if(!$res) { + return $softFail ? null : abort(404); + } + return $res; + } - public static function getMastodon($id, $softFail = false) - { - $account = self::get($id, $softFail); - if(!$account) { - return null; - } + public static function getMastodon($id, $softFail = false) + { + $account = self::get($id, $softFail); + if(!$account) { + return null; + } - if(config('exp.emc') == false) { - return $account; - } + if(config('exp.emc') == false) { + return $account; + } - unset( - $account['header_bg'], - $account['is_admin'], - $account['last_fetched_at'], - $account['local'], - $account['location'], - $account['note_text'], - $account['pronouns'], - $account['website'] - ); + unset( + $account['header_bg'], + $account['is_admin'], + $account['last_fetched_at'], + $account['local'], + $account['location'], + $account['note_text'], + $account['pronouns'], + $account['website'] + ); - $account['avatar_static'] = $account['avatar']; - $account['bot'] = false; - $account['emojis'] = []; - $account['fields'] = []; - $account['header'] = url('/storage/headers/missing.png'); - $account['header_static'] = url('/storage/headers/missing.png'); - $account['last_status_at'] = null; + $account['avatar_static'] = $account['avatar']; + $account['bot'] = false; + $account['emojis'] = []; + $account['fields'] = []; + $account['header'] = url('/storage/headers/missing.png'); + $account['header_static'] = url('/storage/headers/missing.png'); + $account['last_status_at'] = null; - return $account; - } + return $account; + } - public static function del($id) - { - Cache::forget('pf:activitypub:user-object:by-id:' . $id); - return Cache::forget(self::CACHE_KEY . $id); - } + public static function del($id) + { + Cache::forget('pf:activitypub:user-object:by-id:' . $id); + return Cache::forget(self::CACHE_KEY . $id); + } - public static function settings($id) - { - return Cache::remember('profile:compose:settings:' . $id, 604800, function() use($id) { - $settings = UserSetting::whereUserId($id)->first(); - if(!$settings) { - return self::defaultSettings(); - } - return collect($settings) - ->filter(function($item, $key) { - return in_array($key, array_keys(self::defaultSettings())) == true; - }) - ->map(function($item, $key) { - if($key == 'compose_settings') { - $cs = self::defaultSettings()['compose_settings']; - $ms = is_array($item) ? $item : []; - return array_merge($cs, $ms); - } + public static function settings($id) + { + return Cache::remember('profile:compose:settings:' . $id, 604800, function() use($id) { + $settings = UserSetting::whereUserId($id)->first(); + if(!$settings) { + return self::defaultSettings(); + } + return collect($settings) + ->filter(function($item, $key) { + return in_array($key, array_keys(self::defaultSettings())) == true; + }) + ->map(function($item, $key) { + if($key == 'compose_settings') { + $cs = self::defaultSettings()['compose_settings']; + $ms = is_array($item) ? $item : []; + return array_merge($cs, $ms); + } - if($key == 'other') { - $other = self::defaultSettings()['other']; - $mo = is_array($item) ? $item : []; - return array_merge($other, $mo); - } - return $item; - }); - }); - } + if($key == 'other') { + $other = self::defaultSettings()['other']; + $mo = is_array($item) ? $item : []; + return array_merge($other, $mo); + } + return $item; + }); + }); + } - public static function canEmbed($id) - { - return self::settings($id)['other']['disable_embeds'] == false; - } + public static function canEmbed($id) + { + return self::settings($id)['other']['disable_embeds'] == false; + } - public static function defaultSettings() - { - return [ - 'crawlable' => true, - 'public_dm' => false, - 'reduce_motion' => false, - 'high_contrast_mode' => false, - 'video_autoplay' => false, - 'show_profile_follower_count' => true, - 'show_profile_following_count' => true, - 'compose_settings' => [ - 'default_scope' => 'public', - 'default_license' => 1, - 'media_descriptions' => false - ], - 'other' => [ - 'advanced_atom' => false, - 'disable_embeds' => false, - 'mutual_mention_notifications' => false, - 'hide_collections' => false, - 'hide_like_counts' => false, - 'hide_groups' => false, - 'hide_stories' => false, - 'disable_cw' => false, - ] - ]; - } + public static function defaultSettings() + { + return [ + 'crawlable' => true, + 'public_dm' => false, + 'reduce_motion' => false, + 'high_contrast_mode' => false, + 'video_autoplay' => false, + 'show_profile_follower_count' => true, + 'show_profile_following_count' => true, + 'compose_settings' => [ + 'default_scope' => 'public', + 'default_license' => 1, + 'media_descriptions' => false + ], + 'other' => [ + 'advanced_atom' => false, + 'disable_embeds' => false, + 'mutual_mention_notifications' => false, + 'hide_collections' => false, + 'hide_like_counts' => false, + 'hide_groups' => false, + 'hide_stories' => false, + 'disable_cw' => false, + ] + ]; + } - public static function syncPostCount($id) - { - $profile = Profile::find($id); + public static function syncPostCount($id) + { + $profile = Profile::find($id); - if(!$profile) { - return false; - } + if(!$profile) { + return false; + } - $key = self::CACHE_KEY . 'pcs:' . $id; + $key = self::CACHE_KEY . 'pcs:' . $id; - if(Cache::has($key)) { - return; - } + if(Cache::has($key)) { + return; + } - $count = Status::whereProfileId($id) - ->whereNull('in_reply_to_id') - ->whereNull('reblog_of_id') - ->whereIn('scope', ['public', 'unlisted', 'private']) - ->count(); + $count = Status::whereProfileId($id) + ->whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereIn('scope', ['public', 'unlisted', 'private']) + ->count(); - $profile->status_count = $count; - $profile->save(); + $profile->status_count = $count; + $profile->save(); - Cache::put($key, 1, 900); - return true; - } + Cache::put($key, 1, 900); + return true; + } - public static function usernameToId($username) - { - $key = self::CACHE_KEY . 'u2id:' . hash('sha256', $username); - return Cache::remember($key, 900, function() use($username) { - $s = Str::of($username); - if($s->contains('@') && !$s->startsWith('@')) { - $username = "@{$username}"; - } - $profile = DB::table('profiles') - ->whereUsername($username) - ->first(); - if(!$profile) { - return null; - } - return (string) $profile->id; - }); - } + public static function usernameToId($username) + { + $key = self::CACHE_KEY . 'u2id:' . hash('sha256', $username); + return Cache::remember($key, 14400, function() use($username) { + $s = Str::of($username); + if($s->contains('@') && !$s->startsWith('@')) { + $username = "@{$username}"; + } + $profile = DB::table('profiles') + ->whereUsername($username) + ->first(); + if(!$profile) { + return null; + } + return (string) $profile->id; + }); + } - public static function hiddenFollowers($id) - { - $account = self::get($id, true); - if(!$account || !isset($account['local']) || $account['local'] == false) { - return false; - } + public static function hiddenFollowers($id) + { + $account = self::get($id, true); + if(!$account || !isset($account['local']) || $account['local'] == false) { + return false; + } - return Cache::remember('pf:acct:settings:hidden-followers:' . $id, 43200, function() use($id) { - $user = User::whereProfileId($id)->first(); - if(!$user) { - return false; - } - $settings = UserSetting::whereUserId($user->id)->first(); - if($settings) { - return $settings->show_profile_follower_count == false; - } - return false; - }); - } + return Cache::remember('pf:acct:settings:hidden-followers:' . $id, 43200, function() use($id) { + $user = User::whereProfileId($id)->first(); + if(!$user) { + return false; + } + $settings = UserSetting::whereUserId($user->id)->first(); + if($settings) { + return $settings->show_profile_follower_count == false; + } + return false; + }); + } - public static function hiddenFollowing($id) - { - $account = self::get($id, true); - if(!$account || !isset($account['local']) || $account['local'] == false) { - return false; - } + public static function hiddenFollowing($id) + { + $account = self::get($id, true); + if(!$account || !isset($account['local']) || $account['local'] == false) { + return false; + } - return Cache::remember('pf:acct:settings:hidden-following:' . $id, 43200, function() use($id) { - $user = User::whereProfileId($id)->first(); - if(!$user) { - return false; - } - $settings = UserSetting::whereUserId($user->id)->first(); - if($settings) { - return $settings->show_profile_following_count == false; - } - return false; - }); - } + return Cache::remember('pf:acct:settings:hidden-following:' . $id, 43200, function() use($id) { + $user = User::whereProfileId($id)->first(); + if(!$user) { + return false; + } + $settings = UserSetting::whereUserId($user->id)->first(); + if($settings) { + return $settings->show_profile_following_count == false; + } + return false; + }); + } + + public static function setLastActive($id = false) + { + if(!$id) { return; } + $key = 'user:last_active_at:id:' . $id; + if(!Cache::has($key)) { + $user = User::find($id); + if(!$user) { return; } + $user->last_active_at = now(); + $user->save(); + Cache::put($key, 1, 14400); + } + return; + } } From b6419545491623648e410b5a73b10887325ece3d Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 13 Dec 2023 06:49:00 -0700 Subject: [PATCH 2/3] Update ApiV1Controller, set last_active_at --- app/Http/Controllers/Api/ApiV1Controller.php | 61 ++++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 84569fa5b..f5e1202c0 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -189,6 +189,7 @@ class ApiV1Controller extends Controller abort_if(!$user, 403); abort_if($user->status != null, 403); + AccountService::setLastActive($user->id); $res = $request->has(self::PF_API_ENTITY_KEY) ? AccountService::get($user->profile_id) : AccountService::getMastodon($user->profile_id); @@ -247,6 +248,7 @@ class ApiV1Controller extends Controller ]); $user = $request->user(); + AccountService::setLastActive($user->id); $profile = $user->profile; $settings = $user->settings; @@ -754,6 +756,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $target = Profile::where('id', '!=', $user->profile_id) ->whereNull('status') @@ -838,6 +841,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $target = Profile::where('id', '!=', $user->profile_id) ->whereNull('status') @@ -941,6 +945,7 @@ class ApiV1Controller extends Controller ]); $user = $request->user(); + AccountService::setLastActive($user->id); $query = $request->input('q'); $limit = $request->input('limit') ?? 20; $resolve = (bool) $request->input('resolve', false); @@ -1013,6 +1018,7 @@ class ApiV1Controller extends Controller $user = $request->user(); $pid = $user->profile_id ?? $user->profile->id; + AccountService::setLastActive($user->id); if(intval($id) === intval($pid)) { abort(400, 'You cannot block yourself'); @@ -1105,6 +1111,7 @@ class ApiV1Controller extends Controller $user = $request->user(); $pid = $user->profile_id ?? $user->profile->id; + AccountService::setLastActive($user->id); if(intval($id) === intval($pid)) { abort(400, 'You cannot unblock yourself'); @@ -1237,6 +1244,8 @@ class ApiV1Controller extends Controller $user = $request->user(); + AccountService::setLastActive($user->id); + $status = StatusService::getMastodon($id, false); abort_unless($status, 400); @@ -1296,6 +1305,8 @@ class ApiV1Controller extends Controller $user = $request->user(); + AccountService::setLastActive($user->id); + $status = Status::findOrFail($id); if(intval($status->profile_id) !== intval($user->profile_id)) { @@ -1611,6 +1622,7 @@ class ApiV1Controller extends Controller ]); $user = $request->user(); + AccountService::setLastActive($user->id); if($user->last_active_at == null) { return []; @@ -1732,6 +1744,7 @@ class ApiV1Controller extends Controller ]); $user = $request->user(); + AccountService::setLastActive($user->id); $media = Media::whereUserId($user->id) ->whereProfileId($user->profile_id) @@ -1778,6 +1791,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $media = Media::whereUserId($user->id) ->whereNull('status_id') @@ -1821,6 +1835,8 @@ class ApiV1Controller extends Controller return []; } + AccountService::setLastActive($user->id); + if(empty($request->file('file'))) { return response('', 422); } @@ -2065,6 +2081,8 @@ class ApiV1Controller extends Controller 'min_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX, 'max_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX, 'since_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX, + 'types[]' => 'sometimes|array', + 'type' => 'sometimes|string|in:mention,reblog,follow,favourite' ]); $pid = $request->user()->profile_id; @@ -2078,28 +2096,28 @@ class ApiV1Controller extends Controller $min = 1; } + $types = $request->input('types'); + $maxId = null; $minId = null; + AccountService::setLastActive($request->user()->id); - if($max) { - $res = NotificationService::getMaxMastodon($pid, $max, $limit); - $ids = NotificationService::getRankedMaxId($pid, $max, $limit); - if(!empty($ids)) { - $maxId = max($ids); - $minId = min($ids); - } - } else { - $res = NotificationService::getMinMastodon($pid, $min ?? $since, $limit); - $ids = NotificationService::getRankedMinId($pid, $min ?? $since, $limit); - if(!empty($ids)) { - $maxId = max($ids); - $minId = min($ids); - } + $res = $max ? + NotificationService::getMaxMastodon($pid, $max, $limit) : + NotificationService::getMinMastodon($pid, $min ?? $since, $limit); + $ids = $max ? + NotificationService::getRankedMaxId($pid, $max, $limit) : + NotificationService::getRankedMinId($pid, $min ?? $since, $limit); + if(!empty($ids)) { + $maxId = max($ids); + $minId = min($ids); } - if(empty($res) && !Cache::has('pf:services:notifications:hasSynced:'.$pid)) { - Cache::put('pf:services:notifications:hasSynced:'.$pid, 1, 1209600); - NotificationService::warmCache($pid, 400, true); + if(empty($res)) { + if(!Cache::has('pf:services:notifications:hasSynced:'.$pid)) { + Cache::put('pf:services:notifications:hasSynced:'.$pid, 1, 1209600); + NotificationService::warmCache($pid, 400, true); + } } $baseUrl = config('app.url') . '/api/v1/notifications?limit=' . $limit . '&'; @@ -2153,6 +2171,7 @@ class ApiV1Controller extends Controller $inTypes = $includeReblogs ? ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album', 'share'] : ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']; + AccountService::setLastActive($request->user()->id); if(config('exp.cached_home_timeline')) { $paddedLimit = $includeReblogs ? $limit + 10 : $limit + 50; @@ -2402,6 +2421,7 @@ class ApiV1Controller extends Controller $remote = $request->has('remote'); $local = $request->has('local'); $filtered = $user ? UserFilterService::filters($user->profile_id) : []; + AccountService::setLastActive($user->id); if($remote && config('instance.timeline.network.cached')) { Cache::remember('api:v1:timelines:network:cache_check', 10368000, function() { @@ -2593,7 +2613,7 @@ class ApiV1Controller extends Controller public function statusById(Request $request, $id) { abort_if(!$request->user(), 403); - + AccountService::setLastActive($request->user()->id); $pid = $request->user()->profile_id; $res = $request->has(self::PF_API_ENTITY_KEY) ? StatusService::get($id, false) : StatusService::getMastodon($id, false); @@ -2637,6 +2657,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $pid = $user->profile_id; $status = StatusService::getMastodon($id, false); @@ -3107,7 +3128,7 @@ class ApiV1Controller extends Controller public function statusDelete(Request $request, $id) { abort_if(!$request->user(), 403); - + AccountService::setLastActive($request->user()->id); $status = Status::whereProfileId($request->user()->profile->id) ->findOrFail($id); @@ -3135,6 +3156,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $status = Status::whereScope('public')->findOrFail($id); if(intval($status->profile_id) !== intval($user->profile_id)) { @@ -3181,6 +3203,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + AccountService::setLastActive($user->id); $status = Status::whereScope('public')->findOrFail($id); if(intval($status->profile_id) !== intval($user->profile_id)) { From f22a36fe308f9d51b67ae738d78bb9e78ea6cdb3 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 13 Dec 2023 06:49:51 -0700 Subject: [PATCH 3/3] Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6e608d69..93b545a30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,8 @@ - Update Timeline.vue, improve CHT pagination ([9c43e7e2](https://github.com/pixelfed/pixelfed/commit/9c43e7e2)) - Update HomeFeedPipeline, fix StatusService validation ([041c0135](https://github.com/pixelfed/pixelfed/commit/041c0135)) - Update Inbox, improve tombstone query efficiency ([759a4393](https://github.com/pixelfed/pixelfed/commit/759a4393)) +- Update AccountService, add setLastActive method ([ebbd98e7](https://github.com/pixelfed/pixelfed/commit/ebbd98e7)) +- Update ApiV1Controller, set last_active_at ([b6419545](https://github.com/pixelfed/pixelfed/commit/b6419545)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.9 (2023-08-21)](https://github.com/pixelfed/pixelfed/compare/v0.11.8...v0.11.9)