diff --git a/CHANGELOG.md b/CHANGELOG.md index 586193a53..81e36c387 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,13 @@ - Updated MediaStorageService, improve head checks to fix failed jobs. ([1769cdfd](https://github.com/pixelfed/pixelfed/commit/1769cdfd)) - Updated user admin, remove expensive db query and add search. ([8feeadbf](https://github.com/pixelfed/pixelfed/commit/8feeadbf)) - Updated Compose apis, prevent private accounts from posting public or unlisted scopes. ([f53bfa6f](https://github.com/pixelfed/pixelfed/commit/f53bfa6f)) +- Updated font icons, use font-display:swap. ([77d4353a](https://github.com/pixelfed/pixelfed/commit/77d4353a)) +- Updated ComposeModal, limit visibility scope for private accounts. ([001d4105](https://github.com/pixelfed/pixelfed/commit/001d4105)) +- Updated ComposeController, add autocomplete apis for hashtags and mentions. ([f0e48a09](https://github.com/pixelfed/pixelfed/commit/f0e48a09)) +- Updated StatusController, invalidate profile embed cache on status delete. ([9c8a87c3](https://github.com/pixelfed/pixelfed/commit/9c8a87c3)) +- Updated moderation api, invalidate profile embed. ([b2501bfc](https://github.com/pixelfed/pixelfed/commit/b2501bfc)) +- Updated Nodeinfo util, use last_active_at for monthly active user count. ([d200c12c](https://github.com/pixelfed/pixelfed/commit/d200c12c)) +- Updated PhotoPresenter, add width and height to images. ([3f8202e2](https://github.com/pixelfed/pixelfed/commit/3f8202e2)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10) diff --git a/app/Http/Controllers/ComposeController.php b/app/Http/Controllers/ComposeController.php index a51e2ab04..001fc66c1 100644 --- a/app/Http/Controllers/ComposeController.php +++ b/app/Http/Controllers/ComposeController.php @@ -7,6 +7,7 @@ use Auth, Cache, Storage, URL; use Carbon\Carbon; use App\{ Avatar, + Hashtag, Like, Media, MediaTag, @@ -304,6 +305,72 @@ class ComposeController extends Controller return $places; } + public function searchMentionAutocomplete(Request $request) + { + abort_if(!$request->user(), 403); + + $this->validate($request, [ + 'q' => 'required|string|min:2|max:50' + ]); + + $q = $request->input('q'); + + if(Str::of($q)->startsWith('@')) { + if(strlen($q) < 3) { + return []; + } + } + + $blocked = UserFilter::whereFilterableType('App\Profile') + ->whereFilterType('block') + ->whereFilterableId($request->user()->profile_id) + ->pluck('user_id'); + + $blocked->push($request->user()->profile_id); + + $results = Profile::select('id','domain','username') + ->whereNotIn('id', $blocked) + ->where('username','like','%'.$q.'%') + ->groupBy('domain') + ->limit(15) + ->get() + ->map(function($profile) { + $username = $profile->domain ? substr($profile->username, 1) : $profile->username; + return [ + 'key' => '@' . str_limit($username, 30), + 'value' => $username, + ]; + }); + + return $results; + } + + public function searchHashtagAutocomplete(Request $request) + { + abort_if(!$request->user(), 403); + + $this->validate($request, [ + 'q' => 'required|string|min:2|max:50' + ]); + + $q = $request->input('q'); + + $results = Hashtag::select('slug') + ->where('slug', 'like', '%'.$q.'%') + ->whereIsNsfw(false) + ->whereIsBanned(false) + ->limit(5) + ->get() + ->map(function($tag) { + return [ + 'key' => '#' . $tag->slug, + 'value' => $tag->slug + ]; + }); + + return $results; + } + public function store(Request $request) { $this->validate($request, [ diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index 1a0af7d1a..2df78dee3 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -132,13 +132,15 @@ class InternalApiController extends Controller public function statusReplies(Request $request, int $id) { + $this->validate($request, [ + 'limit' => 'nullable|int|min:1|max:6' + ]); $parent = Status::whereScope('public')->findOrFail($id); - + $limit = $request->input('limit') ?? 3; $children = Status::whereInReplyToId($parent->id) ->orderBy('created_at', 'desc') - ->take(3) + ->take($limit) ->get(); - $resource = new Fractal\Resource\Collection($children, new StatusTransformer()); $res = $this->fractal->createData($resource)->toArray(); @@ -310,6 +312,10 @@ class InternalApiController extends Controller } break; } + + Cache::forget('_api:statuses:recent_9:' . $status->profile_id); + Cache::forget('profile:embed:' . $status->profile_id); + return ['msg' => 200]; } diff --git a/app/Http/Controllers/PublicApiController.php b/app/Http/Controllers/PublicApiController.php index 1402940ef..c1e8ef9f0 100644 --- a/app/Http/Controllers/PublicApiController.php +++ b/app/Http/Controllers/PublicApiController.php @@ -166,7 +166,7 @@ class PublicApiController extends Controller ->whereNull('reblog_of_id') ->whereIn('scope', $scope) ->whereNotIn('profile_id', $filtered) - ->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') + ->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') ->where('id', '>=', $request->min_id) ->orderBy('id', 'desc') ->paginate($limit); @@ -176,7 +176,7 @@ class PublicApiController extends Controller ->whereNull('reblog_of_id') ->whereIn('scope', $scope) ->whereNotIn('profile_id', $filtered) - ->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') + ->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') ->where('id', '<=', $request->max_id) ->orderBy('id', 'desc') ->paginate($limit); @@ -186,7 +186,7 @@ class PublicApiController extends Controller ->whereNull('reblog_of_id') ->whereIn('scope', $scope) ->whereNotIn('profile_id', $filtered) - ->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') + ->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at') ->orderBy('id', 'desc') ->paginate($limit); } diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php index 17ce59fb2..cda8c77ee 100644 --- a/app/Http/Controllers/StatusController.php +++ b/app/Http/Controllers/StatusController.php @@ -74,6 +74,12 @@ class StatusController extends Controller } $template = $status->in_reply_to_id ? 'status.reply' : 'status.show'; + // $template = $status->type === 'video' && + // $request->has('video_beta') && + // $request->video_beta == 1 && + // $request->user() ? + // 'status.show_video' : 'status.show'; + return view($template, compact('user', 'status')); } @@ -212,6 +218,7 @@ class StatusController extends Controller Cache::forget('_api:statuses:recent_9:' . $status->profile_id); Cache::forget('profile:status_count:' . $status->profile_id); + Cache::forget('profile:embed:' . $status->profile_id); StatusService::del($status->id); if ($status->profile_id == $user->profile->id || $user->is_admin == true) { Cache::forget('profile:status_count:'.$status->profile_id); diff --git a/app/Util/Site/Nodeinfo.php b/app/Util/Site/Nodeinfo.php index 1c9920441..022615e37 100644 --- a/app/Util/Site/Nodeinfo.php +++ b/app/Util/Site/Nodeinfo.php @@ -12,24 +12,31 @@ class Nodeinfo { { $res = Cache::remember('api:nodeinfo', now()->addMinutes(15), function () { $activeHalfYear = Cache::remember('api:nodeinfo:ahy', now()->addHours(12), function() { + // todo: replace with last_active_at after July 9, 2021 (96afc3e781) $count = collect([]); $likes = Like::select('profile_id')->with('actor')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray(); $count = $count->merge($likes); $statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray(); $count = $count->merge($statuses); - $profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('id')->pluck('id')->toArray(); + $profiles = User::select('profile_id', 'last_active_at') + ->whereNotNull('last_active_at') + ->where('last_active_at', '>', now()->subMonths(6)) + ->pluck('profile_id') + ->toArray(); + $newProfiles = User::select('profile_id', 'last_active_at', 'created_at') + ->whereNull('last_active_at') + ->where('created_at', '>', now()->subMonths(6)) + ->pluck('profile_id') + ->toArray(); + $count = $count->merge($newProfiles); $count = $count->merge($profiles); return $count->unique()->count(); }); - $activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(12), function() { - $count = collect([]); - $likes = Like::select('profile_id')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray(); - $count = $count->merge($likes); - $statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray(); - $count = $count->merge($statuses); - $profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('id')->pluck('id')->toArray(); - $count = $count->merge($profiles); - return $count->unique()->count(); + $activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(2), function() { + return User::select('last_active_at') + ->where('last_active_at', '>', now()->subMonths(1)) + ->orWhere('created_at', '>', now()->subMonths(1)) + ->count(); }); return [ 'metadata' => [ diff --git a/public/css/app.css b/public/css/app.css index 9bde4d09c..4d055ba6e 100644 Binary files a/public/css/app.css and b/public/css/app.css differ diff --git a/public/css/appdark.css b/public/css/appdark.css index b05ad48a6..4316e2ca4 100644 Binary files a/public/css/appdark.css and b/public/css/appdark.css differ diff --git a/public/css/landing.css b/public/css/landing.css index 8403b1bde..39b77f2c9 100644 Binary files a/public/css/landing.css and b/public/css/landing.css differ diff --git a/public/css/quill.css b/public/css/quill.css index f11350023..a1b638f27 100644 Binary files a/public/css/quill.css and b/public/css/quill.css differ diff --git a/public/js/compose.js b/public/js/compose.js index eaf9b1b50..2eea9e6e7 100644 Binary files a/public/js/compose.js and b/public/js/compose.js differ diff --git a/public/js/profile.js b/public/js/profile.js index e7a1361d3..e74c11967 100644 Binary files a/public/js/profile.js and b/public/js/profile.js differ diff --git a/public/js/rempos.js b/public/js/rempos.js index a5cd7c1ba..8c3861383 100644 Binary files a/public/js/rempos.js and b/public/js/rempos.js differ diff --git a/public/js/status.js b/public/js/status.js index 78d2c8efe..78bfd4b41 100644 Binary files a/public/js/status.js and b/public/js/status.js differ diff --git a/public/js/timeline.js b/public/js/timeline.js index f6c7c2080..e9adcae1d 100644 Binary files a/public/js/timeline.js and b/public/js/timeline.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 167da845a..ef93cf5dd 100644 Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ diff --git a/resources/assets/js/components/ComposeModal.vue b/resources/assets/js/components/ComposeModal.vue index 729cc03aa..f700f0373 100644 --- a/resources/assets/js/components/ComposeModal.vue +++ b/resources/assets/js/components/ComposeModal.vue @@ -479,9 +479,26 @@
- -
-Error: Problem rendering preview.
-- - - For information about COVID-19, {{config.features.label.covid.org}} - - - - -
-Hello, {{profile.acct}}
--
Start following people to build your timeline.
- -{{profile.username || 'loading...'}}
-{{profile.display_name || 'loading...'}}
-+ +
+{{scope == 'local' ? 'Public' : 'Home'}} Timeline
@@ -426,371 +24,788 @@
Error: Problem rendering preview.
++ + + For information about COVID-19, {{config.features.label.covid.org}} + + + +
-
-
- {{s.favourites_count == 1 ? '1 like' : s.favourites_count+' likes'}} - - -
+Hello, {{profile.acct}}
++
Start following people to build your timeline.
+ +{{profile.username || 'loading...'}}
+{{profile.display_name || 'loading...'}}
+Comments
++ + + +
+No comments yet
++
+
+
+
-
-
-
-
- - {{reply.account.username}} - - - - - - - - - - - -
-