فهرست منبع

Update ApiV1Controller, implement better limit logic to gracefully handle requests with limits that exceed the max

Daniel Supernault 1 سال پیش
والد
کامیت
1f74a95d0c
1فایلهای تغییر یافته به همراه128 افزوده شده و 43 حذف شده
  1. 128 43
      app/Http/Controllers/Api/ApiV1Controller.php

+ 128 - 43
app/Http/Controllers/Api/ApiV1Controller.php

@@ -496,9 +496,12 @@ class ApiV1Controller extends Controller
         abort_if(!$account, 404);
         $pid = $request->user()->profile_id;
         $this->validate($request, [
-            'limit' => 'sometimes|integer|min:1|max:80'
+            'limit' => 'sometimes|integer|min:1'
         ]);
         $limit = $request->input('limit', 10);
+        if($limit > 80) {
+            $limit = 80;
+        }
         $napi = $request->has(self::PF_API_ENTITY_KEY);
 
         if($account && strpos($account['acct'], '@') != -1) {
@@ -594,9 +597,12 @@ class ApiV1Controller extends Controller
         abort_if(!$account, 404);
         $pid = $request->user()->profile_id;
         $this->validate($request, [
-            'limit' => 'sometimes|integer|min:1|max:80'
+            'limit' => 'sometimes|integer|min:1'
         ]);
         $limit = $request->input('limit', 10);
+        if($limit > 80) {
+            $limit = 80;
+        }
         $napi = $request->has(self::PF_API_ENTITY_KEY);
 
         if($account && strpos($account['acct'], '@') != -1) {
@@ -698,7 +704,7 @@ class ApiV1Controller extends Controller
             '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:100'
+            'limit' => 'nullable|integer|min:1'
         ]);
 
         $napi = $request->has(self::PF_API_ENTITY_KEY);
@@ -713,7 +719,10 @@ class ApiV1Controller extends Controller
             abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
         }
 
-        $limit = $request->limit ?? 20;
+        $limit = $request->input('limit') ?? 20;
+        if($limit > 40) {
+            $limit = 40;
+        }
         $max_id = $request->max_id;
         $min_id = $request->min_id;
 
@@ -959,12 +968,16 @@ class ApiV1Controller extends Controller
         abort_if(!$request->user(), 403);
 
         $this->validate($request, [
-            'id'    => 'required|array|min:1|max:20',
+            'id'    => 'required|array|min:1',
             'id.*'  => 'required|integer|min:1|max:' . PHP_INT_MAX
         ]);
+        $ids = $request->input('id');
+        if(count($ids) > 20) {
+            $ids = collect($ids)->take(20)->toArray();
+        }
         $napi = $request->has(self::PF_API_ENTITY_KEY);
         $pid = $request->user()->profile_id ?? $request->user()->profile->id;
-        $res = collect($request->input('id'))
+        $res = collect($ids)
             ->filter(function($id) use($pid) {
                 return intval($id) !== intval($pid);
             })
@@ -989,8 +1002,8 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'q'         => 'required|string|min:1|max:255',
-            'limit'     => 'nullable|integer|min:1|max:40',
+            'q'         => 'required|string|min:1|max:30',
+            'limit'     => 'nullable|integer|min:1',
             'resolve'   => 'nullable'
         ]);
 
@@ -1000,22 +1013,23 @@ class ApiV1Controller extends Controller
         AccountService::setLastActive($user->id);
         $query = $request->input('q');
         $limit = $request->input('limit') ?? 20;
-        $resolve = (bool) $request->input('resolve', false);
-        $q = '%' . $query . '%';
-
-        $profiles = Cache::remember('api:v1:accounts:search:' . sha1($query) . ':limit:' . $limit, 86400, function() use($q, $limit) {
-            return Profile::whereNull('status')
-                ->where('username', 'like', $q)
-                ->orWhere('name', 'like', $q)
-                ->limit($limit)
-                ->pluck('id')
-                ->map(function($id) {
-                    return AccountService::getMastodon($id);
-                })
-                ->filter(function($account) {
-                    return $account && isset($account['id']);
-                });
-        });
+        if($limit > 20) {
+            $limit = 20;
+        }
+        $resolve = $request->boolean('resolve', false);
+        $q = $query . '%';
+
+        $profiles = Profile::where('username', 'like', $q)
+            ->orderByDesc('followers_count')
+            ->limit($limit)
+            ->pluck('id')
+            ->map(function($id) {
+                return AccountService::getMastodon($id);
+            })
+            ->filter(function($account) {
+                return $account && isset($account['id']);
+            })
+            ->values();
 
         return $this->json($profiles);
     }
@@ -1033,20 +1047,25 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit'     => 'nullable|integer|min:1|max:40',
-            'page'      => 'nullable|integer|min:1|max:10'
+            'limit'     => 'sometimes|integer|min:1',
+            'page'      => 'sometimes|integer|min:1'
         ]);
 
         $user = $request->user();
         $limit = $request->input('limit') ?? 40;
+        if($limit > 80) {
+            $limit = 80;
+        }
 
-        $blocked = UserFilter::select('filterable_id','filterable_type','filter_type','user_id')
+        $blocks = UserFilter::select('filterable_id','filterable_type','filter_type','user_id')
             ->whereUserId($user->profile_id)
             ->whereFilterableType('App\Profile')
             ->whereFilterType('block')
             ->orderByDesc('id')
             ->simplePaginate($limit)
-            ->pluck('filterable_id')
+            ->withQueryString();
+
+        $res = $blocks->pluck('filterable_id')
             ->map(function($id) {
                 return AccountService::get($id, true);
             })
@@ -1055,7 +1074,23 @@ class ApiV1Controller extends Controller
             })
             ->values();
 
-        return $this->json($blocked);
+        $baseUrl = config('app.url') . '/api/v1/blocks?limit=' . $limit . '&';
+        $next = $blocks->nextPageUrl();
+        $prev = $blocks->previousPageUrl();
+
+        if($next && !$prev) {
+            $link = '<'.$next.'>; rel="next"';
+        }
+
+        if(!$next && $prev) {
+            $link = '<'.$prev.'>; rel="prev"';
+        }
+
+        if($next && $prev) {
+            $link = '<'.$next.'>; rel="next",<'.$prev.'>; rel="prev"';
+        }
+        $headers = isset($link) ? ['Link' => $link] : [];
+        return $this->json($res, 200, $headers);
     }
 
     /**
@@ -1247,13 +1282,16 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit' => 'sometimes|integer|min:1|max:40'
+            'limit' => 'sometimes|integer|min:1'
         ]);
 
         $user = $request->user();
         $maxId = $request->input('max_id');
         $minId = $request->input('min_id');
         $limit = $request->input('limit') ?? 10;
+        if($limit > 40) {
+            $limit = 40;
+        }
 
         $res = Like::whereProfileId($user->profile_id)
             ->when($maxId, function($q, $maxId) {
@@ -1620,7 +1658,7 @@ class ApiV1Controller extends Controller
                 'thumbnail' => config_cache('app.banner_image') ?? url(Storage::url('public/headers/default.jpg')),
                 'languages' => [config('app.locale')],
                 'registrations' => (bool) config_cache('pixelfed.open_registration'),
-                'approval_required' => false,
+                'approval_required' => false, // (bool) config_cache('instance.curated_registration.enabled'),
                 'contact_account' => $contact,
                 'rules' => $rules,
                 'configuration' => [
@@ -2049,18 +2087,23 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit' => 'nullable|integer|min:1|max:40'
+            'limit' => 'sometimes|integer|min:1'
         ]);
 
         $user = $request->user();
         $limit = $request->input('limit', 40);
+        if($limit > 80) {
+            $limit = 80;
+        }
 
         $mutes = UserFilter::whereUserId($user->profile_id)
             ->whereFilterableType('App\Profile')
             ->whereFilterType('mute')
             ->orderByDesc('id')
             ->simplePaginate($limit)
-            ->pluck('filterable_id')
+            ->withQueryString();
+
+        $res = $mutes->pluck('filterable_id')
             ->map(function($id) {
                 return AccountService::get($id, true);
             })
@@ -2069,7 +2112,23 @@ class ApiV1Controller extends Controller
             })
             ->values();
 
-        return $this->json($mutes);
+        $baseUrl = config('app.url') . '/api/v1/mutes?limit=' . $limit . '&';
+        $next = $mutes->nextPageUrl();
+        $prev = $mutes->previousPageUrl();
+
+        if($next && !$prev) {
+            $link = '<'.$next.'>; rel="next"';
+        }
+
+        if(!$next && $prev) {
+            $link = '<'.$prev.'>; rel="prev"';
+        }
+
+        if($next && $prev) {
+            $link = '<'.$next.'>; rel="next",<'.$prev.'>; rel="prev"';
+        }
+        $headers = isset($link) ? ['Link' => $link] : [];
+        return $this->json($res, 200, $headers);
     }
 
     /**
@@ -2181,7 +2240,7 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit' => 'nullable|integer|min:1|max:100',
+            'limit' => 'sometimes|integer|min:1',
             '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,
@@ -2191,6 +2250,9 @@ class ApiV1Controller extends Controller
 
         $pid = $request->user()->profile_id;
         $limit = $request->input('limit', 20);
+        if($limit > 40) {
+            $limit = 40;
+        }
 
         $since = $request->input('since_id');
         $min = $request->input('min_id');
@@ -2200,6 +2262,10 @@ class ApiV1Controller extends Controller
             $min = 1;
         }
 
+        if($since) {
+            $min = $since + 1;
+        }
+
         $types = $request->input('types');
 
         $maxId = null;
@@ -2261,7 +2327,7 @@ class ApiV1Controller extends Controller
             'page'        => 'sometimes|integer|max:40',
             'min_id'      => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
             'max_id'      => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
-            'limit'       => 'sometimes|integer|min:1|max:40',
+            'limit'       => 'sometimes|integer|min:1',
             'include_reblogs' => 'sometimes',
         ]);
 
@@ -2270,6 +2336,9 @@ class ApiV1Controller extends Controller
         $min = $request->input('min_id');
         $max = $request->input('max_id');
         $limit = $request->input('limit') ?? 20;
+        if($limit > 40) {
+            $limit = 40;
+        }
         $pid = $request->user()->profile_id;
         $includeReblogs = $request->filled('include_reblogs') ? $request->boolean('include_reblogs') : false;
         $nullFields = $includeReblogs ?
@@ -2515,7 +2584,7 @@ class ApiV1Controller extends Controller
         $this->validate($request,[
           'min_id'      => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
           'max_id'      => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
-          'limit'       => 'nullable|integer|max:100',
+          'limit'       => 'sometimes|integer|min:1',
           'remote'      => 'sometimes',
           'local'       => 'sometimes'
         ]);
@@ -2525,6 +2594,9 @@ class ApiV1Controller extends Controller
         $max = $request->input('max_id');
         $minOrMax = $request->anyFilled(['max_id', 'min_id']);
         $limit = $request->input('limit') ?? 20;
+        if($limit > 40) {
+            $limit = 40;
+        }
         $user = $request->user();
 
         $remote = $request->has('remote');
@@ -3043,10 +3115,13 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit' => 'nullable|integer|min:1|max:80'
+            'limit' => 'sometimes|integer|min:1'
         ]);
 
-        $limit = $request->input('limit', 10);
+        $limit = $request->input('limit', 40);
+        if($limit > 80) {
+            $limit = 80;
+        }
         $user = $request->user();
         $pid = $user->profile_id;
         $status = Status::findOrFail($id);
@@ -3485,7 +3560,7 @@ class ApiV1Controller extends Controller
           'page'        => 'nullable|integer|max:40',
           'min_id'      => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
           'max_id'      => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
-          'limit'       => 'nullable|integer|max:100',
+          'limit'       => 'sometimes|integer|min:1',
           'only_media'  => 'sometimes|boolean',
           '_pe'         => 'sometimes'
         ]);
@@ -3518,6 +3593,9 @@ class ApiV1Controller extends Controller
         $min = $request->input('min_id');
         $max = $request->input('max_id');
         $limit = $request->input('limit', 20);
+        if($limit > 40) {
+            $limit = 40;
+        }
         $onlyMedia = $request->input('only_media', true);
         $pe = $request->has(self::PF_API_ENTITY_KEY);
         $pid = $request->user()->profile_id;
@@ -3547,7 +3625,7 @@ class ApiV1Controller extends Controller
             ->whereStatusVisibility('public')
             ->where('status_id', $dir, $id)
             ->orderBy('status_id', 'desc')
-            ->limit($limit)
+            ->limit(100)
             ->pluck('status_id')
             ->map(function ($i) use($pe) {
                 return $pe ? StatusService::get($i) : StatusService::getMastodon($i);
@@ -3565,6 +3643,7 @@ class ApiV1Controller extends Controller
                 $domain = strtolower(parse_url($i['url'], PHP_URL_HOST));
                 return !in_array($i['account']['id'], $filters) && !in_array($domain, $domainBlocks);
             })
+            ->take($limit)
             ->values()
             ->toArray();
 
@@ -3584,7 +3663,7 @@ class ApiV1Controller extends Controller
         abort_unless($request->user()->tokenCan('read'), 403);
 
         $this->validate($request, [
-            'limit' => 'nullable|integer|min:1|max:40',
+            'limit' => 'sometimes|integer|min:1',
             'max_id' => 'nullable|integer|min:0',
             'since_id' => 'nullable|integer|min:0',
             'min_id' => 'nullable|integer|min:0'
@@ -3593,6 +3672,9 @@ class ApiV1Controller extends Controller
         $pe = $request->has('_pe');
         $pid = $request->user()->profile_id;
         $limit = $request->input('limit') ?? 20;
+        if($limit > 40) {
+            $limit = 40;
+        }
         $max_id = $request->input('max_id');
         $since_id = $request->input('since_id');
         $min_id = $request->input('min_id');
@@ -3758,11 +3840,14 @@ class ApiV1Controller extends Controller
         abort_if(!$request->user(), 403);
 
         $this->validate($request, [
-            'limit' => 'int|min:1|max:10',
+            'limit' => 'sometimes|integer|min:1',
             'sort' => 'in:all,newest,popular'
         ]);
 
         $limit = $request->input('limit', 3);
+        if($limit > 10) {
+            $limit = 10;
+        }
         $pid = $request->user()->profile_id;
         $status = StatusService::getMastodon($id, false);