Преглед изворни кода

Merge pull request #947 from pixelfed/frontend-ui-refactor

Improve Profile performance
daniel пре 6 година
родитељ
комит
4db5362068

+ 2 - 0
app/Http/Controllers/FollowerController.php

@@ -68,7 +68,9 @@ class FollowerController extends Controller
             $follower->delete();
         }
 
+        Cache::forget('profile:following:'.$target->id);
         Cache::forget('profile:followers:'.$target->id);
         Cache::forget('profile:following:'.$user->id);
+        Cache::forget('profile:followers:'.$user->id);
     }
 }

+ 63 - 41
app/Http/Controllers/PublicApiController.php

@@ -328,6 +328,7 @@ class PublicApiController extends Controller
                 ->orWhere('status', '!=', null)
                 ->pluck('id');
         });
+
         $filters = UserFilter::whereUserId($pid)
                   ->whereFilterableType('App\Profile')
                   ->whereIn('filter_type', ['mute', 'block'])
@@ -457,51 +458,72 @@ class PublicApiController extends Controller
             'only_media' => 'nullable',
             'pinned' => 'nullable',
             'exclude_replies' => 'nullable',
-            'max_id' => 'nullable|integer|min:1',
-            'since_id' => 'nullable|integer|min:1',
-            'min_id' => 'nullable|integer|min:1',
+            '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'
         ]);
-        $limit = $request->limit ?? 20;
-        $max_id = $request->max_id ?? false;
-        $min_id = $request->min_id ?? false;
-        $since_id = $request->since_id ?? false;
-        $only_media = $request->only_media ?? false;
-        $user = Auth::user();
-        $account = Profile::whereNull('status')->findOrFail($id);
-        $statuses = Status::whereProfileId($id)
-            ->whereNull('uri');
-
-        if(!$user || $user->profile->id != $account->id && !$user->profile->follows($account)) {
-            $statuses = $statuses->whereVisibility('public');
-        } else {
-            $statuses = $statuses->whereIn('visibility', ['public', 'unlisted', 'private']);
-        }
-        if($only_media == true) {
-            $statuses = $statuses
-                ->whereHas('media')
-                ->whereNull('in_reply_to_id')
-                ->whereNull('reblog_of_id');
-        }
-        if($id == $account->id && !$max_id && !$min_id && !$since_id) {
-            $statuses = $statuses->orderBy('id', 'desc')
-                ->simplePaginate($limit);
-        } else if($since_id) {
-            $statuses = $statuses->where('id', '>', $since_id)
-                ->orderBy('id', 'DESC')
-                ->simplePaginate($limit);
-        } else if($min_id) {
-            $statuses = $statuses->where('id', '>', $min_id)
-                ->orderBy('id', 'ASC')
-                ->simplePaginate($limit);
-        } else if($max_id) {
-            $statuses = $statuses->where('id', '<', $max_id)
-                ->orderBy('id', 'DESC')
-                ->simplePaginate($limit);
+
+        $profile = Profile::whereNull('status')->findOrFail($id);
+
+        $limit = $request->limit ?? 9;
+        $max_id = $request->max_id;
+        $min_id = $request->min_id;
+        $scope = $request->only_media == true ? 
+            ['photo', 'photo:album', 'video', 'video:album'] :
+            ['photo', 'photo:album', 'video', 'video:album', 'share', 'reply'];
+       
+        if($profile->is_private) {
+            if(!Auth::check()) {
+                return response()->json([]);
+            }
+            $pid = Auth::user()->profile->id;
+            $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'] : [];
         } else {
-            $statuses = $statuses->orderBy('id', 'desc')->simplePaginate($limit);
+            if(Auth::check()) {
+                $pid = Auth::user()->profile->id;
+                $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'];
+            } else {
+                $visibility = ['public'];
+            }
         }
-        $resource = new Fractal\Resource\Collection($statuses, new StatusTransformer());
+
+
+        $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',
+            'created_at',
+            'updated_at'
+          )->whereProfileId($profile->id)
+          ->whereIn('type', $scope)
+          ->whereLocal(true)
+          ->whereNull('uri')
+          ->where('id', $dir, $id)
+          ->whereIn('visibility',$visibility)
+          ->orderBy('created_at', 'desc')
+          ->limit($limit)
+          ->get();
+
+        $resource = new Fractal\Resource\Collection($timeline, new StatusTransformer());
         $res = $this->fractal->createData($resource)->toArray();
 
         return response()->json($res);

BIN
public/js/discover.js


BIN
public/js/profile.js


BIN
public/mix-manifest.json


+ 1 - 1
resources/assets/js/components/DiscoverComponent.vue

@@ -1,7 +1,7 @@
 <template>
 <div class="container">
 
-  <section class="mb-5 pb-3 px-2 d-xs-none d-md-block" style="overflow-x: hidden;" v-if="categories.length > 0">
+  <section class="mb-5 pb-3 px-2 d-flex" style="overflow-x: hidden;" v-if="categories.length > 0">
     <a class="bg-dark rounded d-inline-flex align-items-end justify-content-center mr-3 box-shadow" style="width:160px;height:100px;" href="/discover/personal">
       <p class="text-white font-weight-bold" style="text-shadow: 3px 3px 16px #272634;border-bottom: 2px solid #fff;">For You</p>
     </a>

+ 23 - 10
resources/assets/js/components/Profile.vue

@@ -22,7 +22,7 @@
 								<span class="pl-4" v-if="owner">
 									<a class="fas fa-cog fa-lg text-muted" href="/settings/home"></a>
 								</span>
-								<span v-if="!owner && user.hasOwnProperty('id')">
+								<span v-if="profile.id != user.id && user.hasOwnProperty('id')">
 									<span class="pl-4" v-if="relationship.following == true">
 										<button type="button"  class="btn btn-outline-secondary font-weight-bold px-4 py-0" v-on:click="followProfile()">Unfollow</button>
 									</span>
@@ -213,10 +213,12 @@
 						</a>
 					</div>
 				</div>
-				<infinite-loading @infinite="infiniteTimeline">
-					<div slot="no-more"></div>
-					<div slot="no-results"></div>
-				</infinite-loading>
+				<div v-if="timeline.length">
+					<infinite-loading @infinite="infiniteTimeline">
+						<div slot="no-more"></div>
+						<div slot="no-results"></div>
+					</infinite-loading>
+				</div>
 			</div>
 		</div>
 	</div>
@@ -324,6 +326,8 @@ export default {
 			user: {},
 			timeline: [],
 			timelinePage: 2,
+			min_id: 0,
+			max_id: 0,
 			loading: true,
 			owner: false,
 			mode: 'grid',
@@ -368,11 +372,15 @@ export default {
 			axios.get(apiUrl, {
 				params: {
 					only_media: true,
-					page: 1,
+					min_id: 1,
 				}
 			})
 			.then(res => {
-				this.timeline = res.data;
+				let data = res.data;
+				this.timeline = data;
+				let ids = data.map(status => status.id);
+				this.min_id = Math.max(...ids);
+				this.max_id = Math.min(...ids);
 				this.modalStatus = _.first(res.data);
 				this.loading = false;
 				this.ownerCheck();
@@ -393,14 +401,16 @@ export default {
 			let apiUrl = '/api/v1/accounts/' + this.profileId + '/statuses';
 			axios.get(apiUrl, {
 				params: {
-					page: this.timelinePage,
-					only_media: true
+					only_media: true,
+					max_id: this.max_id
 				},
 			}).then(res => {
 				if (res.data.length && this.loading == false) {
 					let data = res.data;
 					this.timeline.push(...data);
-					this.timelinePage += 1;
+					let ids = data.map(status => status.id);
+					this.max_id = Math.min(...ids);
+					this.loading = false;
 					$state.loaded();
 				} else {
 					$state.complete();
@@ -651,6 +661,9 @@ export default {
 			}).then(res => {
 				if(this.relationship.following) {
 					this.profile.followers_count--;
+					if(this.profile.locked == true) {
+						window.location.href = '/';
+					}
 				} else {
 					this.profile.followers_count++;
 				}