diff --git a/CHANGELOG.md b/CHANGELOG.md index 57551cd5c..fbedba16c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,8 @@ - Updated StatusService, add getMastodon method for mastoapi compatibility. ([36a129fe](https://github.com/pixelfed/pixelfed/commit/36a129fe)) - Updated PublicApiController, fix accountStatuses pagination operator. ([85fc9dd0](https://github.com/pixelfed/pixelfed/commit/85fc9dd0)) - Updated PublicApiController, enforce only_media on accountStatuses method. Fixes #3105. ([861a2d36](https://github.com/pixelfed/pixelfed/commit/861a2d36)) +- Updated ApiV1Controller, add mastoapi strict mode. ([46485426](https://github.com/pixelfed/pixelfed/commit/46485426)) +- Updated AccountController, refresh RelationshipService on mute/block. ([6f1b0245](https://github.com/pixelfed/pixelfed/commit/6f1b0245)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.1 (2021-09-07)](https://github.com/pixelfed/pixelfed/compare/v0.11.0...v0.11.1) diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index edbf6a4cc..073bbfa81 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -28,6 +28,7 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter; use App\Transformer\Api\Mastodon\v1\AccountTransformer; use App\Services\AccountService; use App\Services\UserFilterService; +use App\Services\RelationshipService; class AccountController extends Controller { @@ -184,6 +185,7 @@ class AccountController extends Controller Cache::forget("user:filter:list:$pid"); Cache::forget("feature:discover:posts:$pid"); Cache::forget("api:local:exp:rec:$pid"); + RelationshipService::refresh($pid, $profile->id); return redirect()->back(); } @@ -234,6 +236,7 @@ class AccountController extends Controller Cache::forget("user:filter:list:$pid"); Cache::forget("feature:discover:posts:$pid"); Cache::forget("api:local:exp:rec:$pid"); + RelationshipService::refresh($pid, $profile->id); if($request->wantsJson()) { return response()->json([200]); @@ -288,6 +291,7 @@ class AccountController extends Controller $pid = $user->id; Cache::forget("user:filter:list:$pid"); Cache::forget("api:local:exp:rec:$pid"); + RelationshipService::refresh($pid, $profile->id); return redirect()->back(); } @@ -338,6 +342,7 @@ class AccountController extends Controller Cache::forget("user:filter:list:$pid"); Cache::forget("feature:discover:posts:$pid"); Cache::forget("api:local:exp:rec:$pid"); + RelationshipService::refresh($pid, $profile->id); return redirect()->back(); } diff --git a/app/Http/Controllers/Admin/AdminSettingsController.php b/app/Http/Controllers/Admin/AdminSettingsController.php index c033b769b..a245997d8 100644 --- a/app/Http/Controllers/Admin/AdminSettingsController.php +++ b/app/Http/Controllers/Admin/AdminSettingsController.php @@ -170,6 +170,8 @@ trait AdminSettingsController $json[] = $val; ConfigCacheService::put('app.rules', json_encode(array_values($json))); } + Cache::forget('api:v1:instance-data:rules'); + Cache::forget('api:v1:instance-data-response'); } if($request->filled('account_autofollow_usernames')) { diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index b4cc51e93..b27cb2fd1 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -16,6 +16,7 @@ use App\{ Follower, FollowRequest, Hashtag, + Instance, Like, Media, Notification, @@ -64,7 +65,6 @@ use App\Services\{ NotificationService, MediaPathService, PublicTimelineService, - ProfileService, RelationshipService, SearchApiV2Service, StatusService, @@ -142,15 +142,15 @@ class ApiV1Controller extends Controller $id = $request->user()->profile_id; - $res = ProfileService::get($id); + $res = AccountService::getMastodon($id); - $res['source'] = [ - 'privacy' => $res['locked'] ? 'private' : 'public', - 'sensitive' => false, - 'language' => null, - 'note' => '', - 'fields' => [] - ]; + // $res['source'] = [ + // 'privacy' => $res['locked'] ? 'private' : 'public', + // 'sensitive' => false, + // 'language' => null, + // 'note' => '', + // 'fields' => [] + // ]; return response()->json($res); } @@ -164,10 +164,10 @@ class ApiV1Controller extends Controller */ public function accountById(Request $request, $id) { - $profile = Profile::whereNull('status')->findOrFail($id); - $resource = new Fractal\Resource\Item($profile, new AccountTransformer()); - $res = $this->fractal->createData($resource)->toArray(); - + $res = AccountService::getMastodon($id, true); + if(!$res) { + return response()->json(['error' => 'Record not found'], 404); + } return response()->json($res); } @@ -394,7 +394,7 @@ class ApiV1Controller extends Controller MediaSyncLicensePipeline::dispatch($user->id, $request->input('license')); } - $res = AccountService::get($user->profile_id); + $res = AccountService::getMastodon($user->profile_id); $res['bio'] = strip_tags($res['note']); $res = array_merge($res, $other); @@ -508,7 +508,7 @@ class ApiV1Controller extends Controller 'limit' => 'nullable|integer|min:1|max:80' ]); - $profile = AccountService::get($id); + $profile = AccountService::getMastodon($id); abort_if(!$profile, 404); $limit = $request->limit ?? 20; @@ -534,17 +534,12 @@ class ApiV1Controller extends Controller if($pid == $profile['id']) { $visibility = ['public', 'unlisted', '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'] : []; + $following = FollowerService::follows($pid, $profile['id']); + abort_unless($following, 403); + $visibility = ['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']; + $following = FollowerService::follows($pid, $profile['id']); + $visibility = $following ? ['public', 'unlisted', 'private'] : ['public', 'unlisted']; } $dir = $min_id ? '>' : '<'; @@ -560,7 +555,7 @@ class ApiV1Controller extends Controller ->get() ->map(function($s) use($user) { try { - $status = StatusService::get($s->id, false); + $status = StatusService::getMastodon($s->id, false); } catch (\Exception $e) { $status = false; } @@ -968,7 +963,7 @@ class ApiV1Controller extends Controller ->limit($limit) ->get() ->map(function($like) { - $status = StatusService::get($like['status_id'], false); + $status = StatusService::getMastodon($like['status_id'], false); $status['like_id'] = $like->id; $status['liked_at'] = $like->created_at->format('c'); return $status; @@ -1172,49 +1167,53 @@ class ApiV1Controller extends Controller */ public function instance(Request $request) { - $res = Cache::remember('api:v1:instance-data', now()->addMinutes(15), function () { - $rules = config_cache('app.rules') ? collect(json_decode(config_cache('app.rules'), true)) - ->map(function($rule, $key) { - $id = $key + 1; - return [ - 'id' => "{$id}", - 'text' => $rule - ]; - }) - ->toArray() : []; - $res = [ - 'approval_required' => false, - 'contact_account' => null, - 'description' => config_cache('app.description'), - 'email' => config('instance.email'), - 'invites_enabled' => false, - 'rules' => $rules, - 'short_description' => 'Pixelfed - Photo sharing for everyone', - 'languages' => ['en'], - 'max_toot_chars' => (int) config('pixelfed.max_caption_length'), - 'registrations' => (bool) config_cache('pixelfed.open_registration'), - 'stats' => [ - 'user_count' => 0, - 'status_count' => 0, - 'domain_count' => 0 - ], - 'thumbnail' => config('app.url') . '/img/pixelfed-icon-color.png', - 'title' => config_cache('app.name'), - 'uri' => config('pixelfed.domain.app'), - 'urls' => [], - 'version' => '2.7.2 (compatible; Pixelfed ' . config('pixelfed.version') . ')', - 'environment' => [ - 'max_photo_size' => (int) config_cache('pixelfed.max_photo_size'), - 'max_avatar_size' => (int) config('pixelfed.max_avatar_size'), - 'max_caption_length' => (int) config('pixelfed.max_caption_length'), - 'max_bio_length' => (int) config('pixelfed.max_bio_length'), - 'max_album_length' => (int) config_cache('pixelfed.max_album_length'), - 'mobile_apis' => (bool) config_cache('pixelfed.oauth_enabled') + $res = Cache::remember('api:v1:instance-data-response', 900, function () { + $contact = Cache::remember('api:v1:instance-data:contact', 604800, function () { + $admin = User::whereIsAdmin(true)->first(); + return $admin && isset($admin->profile_id) ? + AccountService::getMastodon($admin->profile_id, true) : + null; + }); - ] + $stats = Cache::remember('api:v1:instance-data:stats', 43200, function () { + return [ + 'user_count' => User::count(), + 'status_count' => Status::whereNull('uri')->count(), + 'domain_count' => Instance::count(), + ]; + }); + + $rules = Cache::remember('api:v1:instance-data:rules', 604800, function () { + return config_cache('app.rules') ? + collect(json_decode(config_cache('app.rules'), true)) + ->map(function($rule, $key) { + $id = $key + 1; + return [ + 'id' => "{$id}", + 'text' => $rule + ]; + }) + ->toArray() : []; + }); + + return [ + 'uri' => config('pixelfed.domain.app'), + 'title' => config('app.name'), + 'short_description' => 'Pixelfed is an image sharing platform, an ethical alternative to centralized platforms', + 'description' => 'Pixelfed is an image sharing platform, an ethical alternative to centralized platforms', + 'email' => config('instance.email'), + 'version' => config('pixelfed.version'), + 'urls' => [], + 'stats' => $stats, + 'thumbnail' => url('headers/default.jpg'), + 'languages' => ['en'], + 'registrations' => (bool) config('pixelfed.open_registration'), + 'approval_required' => false, + 'contact_account' => $contact, + 'rules' => $rules ]; - return $res; }); + return response()->json($res); } @@ -1731,7 +1730,7 @@ class ApiV1Controller extends Controller 'id' => $dm->id, 'unread' => false, 'accounts' => [ - AccountService::get($from) + AccountService::getMastodon($from) ], 'last_status' => StatusService::getDirectMessage($dm->status_id) ]; @@ -1784,7 +1783,7 @@ class ApiV1Controller extends Controller $res = collect($feed) ->map(function($k) use($user) { - $status = StatusService::get($k); + $status = StatusService::getMastodon($k); if($user) { $status['favourited'] = (bool) LikeService::liked($user->profile_id, $k); $status['relationship'] = RelationshipService::get($user->profile_id, $status['account']['id']); @@ -1811,7 +1810,7 @@ class ApiV1Controller extends Controller $user = $request->user(); - $res = StatusService::get($id, false); + $res = StatusService::getMastodon($id, false); if(!$res || !isset($res['visibility'])) { abort(404); } @@ -2000,7 +1999,7 @@ class ApiV1Controller extends Controller ->limit($limit) ->get() ->map(function($like) { - $account = AccountService::get($like->profile_id); + $account = AccountService::getMastodon($like->profile_id); $account['follows'] = isset($like->created_at); return $account; }) @@ -2314,10 +2313,10 @@ class ApiV1Controller extends Controller ->limit($limit) ->pluck('status_id') ->filter(function($i) { - return StatusService::get($i); + return StatusService::getMastodon($i); }) ->map(function ($i) { - return StatusService::get($i); + return StatusService::getMastodon($i); }) ->filter() ->values() @@ -2367,7 +2366,7 @@ class ApiV1Controller extends Controller $res = []; foreach($bookmarks as $id) { - $res[] = \App\Services\StatusService::get($id); + $res[] = \App\Services\StatusService::getMastodon($id); } return $res; } @@ -2470,7 +2469,7 @@ class ApiV1Controller extends Controller $filters = UserFilterService::filters($pid); $forYou = DiscoverService::getForYou(); $posts = $forYou->take(50)->map(function($post) { - return StatusService::get($post); + return StatusService::getMastodon($post); }) ->filter(function($post) use($filters) { return $post && @@ -2500,7 +2499,7 @@ class ApiV1Controller extends Controller $limit = $request->input('limit', 3); $pid = $request->user()->profile_id; - $status = StatusService::get($id); + $status = StatusService::getMastodon($id); abort_if(!$status || !in_array($status['visibility'], ['public', 'unlisted']), 404); @@ -2533,7 +2532,7 @@ class ApiV1Controller extends Controller } $data = $ids->map(function($post) use($pid) { - $status = StatusService::get($post->id); + $status = StatusService::getMastodon($post->id); if(!$status || !isset($status['id'])) { return false; @@ -2591,7 +2590,7 @@ class ApiV1Controller extends Controller ->get(); $ids = $ids->map(function($profile) { - return AccountService::get($profile->id); + return AccountService::getMastodon($profile->id); }) ->filter(function($profile) use($pid) { return $profile && diff --git a/app/Services/AccountService.php b/app/Services/AccountService.php index 0410f8f64..62996a838 100644 --- a/app/Services/AccountService.php +++ b/app/Services/AccountService.php @@ -40,6 +40,10 @@ class AccountService return null; } + if(config('exp.emc') == false) { + return $account; + } + unset( $account['header_bg'], $account['is_admin'], diff --git a/app/Services/StatusService.php b/app/Services/StatusService.php index 3532c8733..7d72ccbe0 100644 --- a/app/Services/StatusService.php +++ b/app/Services/StatusService.php @@ -46,6 +46,11 @@ class StatusService if(!$status) { return null; } + + if(config('exp.emc') == false) { + return $status; + } + $status['replies_count'] = $status['reply_count']; unset( $status['_v'], diff --git a/app/Util/Lexer/RestrictedNames.php b/app/Util/Lexer/RestrictedNames.php index e2968036f..059f5bf00 100644 --- a/app/Util/Lexer/RestrictedNames.php +++ b/app/Util/Lexer/RestrictedNames.php @@ -178,6 +178,8 @@ class RestrictedNames 'group', 'groups', 'h', + 'header', + 'headers', 'home', 'help', 'helpcenter', diff --git a/config/exp.php b/config/exp.php index c52614f96..181c49f47 100644 --- a/config/exp.php +++ b/config/exp.php @@ -1,13 +1,37 @@ env('EXP_LC', false), + + // Recommendations (deprecated) 'rec' => false, + + // Loops feature (deprecated) 'loops' => false, + + // Text only posts (alpha) 'top' => env('EXP_TOP', false), + + // Poll statuses (alpha) 'polls' => env('EXP_POLLS', false), + + // Cached public timeline for larger instances (beta) 'cached_public_timeline' => env('EXP_CPT', false), + + // Groups (unreleased) 'gps' => env('EXP_GPS', false), + + // Single page application (beta) 'spa' => true, + + // Enforce Mastoapi Compatibility (alpha) + // Note: this may break 3rd party apps who use non-mastodon compliant fields + 'emc' => env('EXP_EMC', false), ]; diff --git a/public/css/spa.css b/public/css/spa.css index daebf88a3..5013f20b2 100644 Binary files a/public/css/spa.css and b/public/css/spa.css differ diff --git a/public/js/spa.js b/public/js/spa.js index d50699ab9..4d205c564 100644 Binary files a/public/js/spa.js and b/public/js/spa.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 213fb536a..e731f5aa3 100644 Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ diff --git a/resources/views/admin/settings/home.blade.php b/resources/views/admin/settings/home.blade.php index 3952b0491..a9835bf7d 100644 --- a/resources/views/admin/settings/home.blade.php +++ b/resources/views/admin/settings/home.blade.php @@ -1,6 +1,4 @@ -@extends('admin.partial.template') - -@include('admin.settings.sidebar') +@extends('admin.partial.template-full') @section('section')