diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php index 42b0dc93b..5d5a46405 100644 --- a/app/Http/Controllers/ApiController.php +++ b/app/Http/Controllers/ApiController.php @@ -3,10 +3,14 @@ namespace App\Http\Controllers; use App\Http\Controllers\Api\BaseApiController; -use App\Like; +use App\{ + Like, + Profile +}; use Auth; use Cache; use Illuminate\Http\Request; +use App\Services\SuggestionService; class ApiController extends BaseApiController { @@ -39,11 +43,51 @@ class ApiController extends BaseApiController ], 'ab' => [ - 'lc' => config('exp.lc') + 'lc' => config('exp.lc'), + 'rec' => config('exp.rec'), ], ]; }); return response()->json($res); } + public function userRecommendations(Request $request) + { + abort_if(!Auth::check(), 403); + abort_if(!config('exp.rec'), 400); + + $id = Auth::user()->profile->id; + + $following = Cache::get('profile:following:'.$id, []); + $ids = SuggestionService::get(); + + $res = Cache::remember('api:local:exp:rec:'.$id, now()->addMinutes(5), function() use($id, $following, $ids) { + + array_push($following, $id); + + return Profile::select( + 'id', + 'username' + ) + ->whereNotIn('id', $following) + ->whereIn('id', $ids) + ->whereIsPrivate(0) + ->whereNull('status') + ->whereNull('domain') + ->inRandomOrder() + ->take(4) + ->get() + ->map(function($item, $key) { + return [ + 'id' => $item->id, + 'avatar' => $item->avatarUrl(), + 'username' => $item->username, + 'message' => 'Recommended for You' + ]; + }); + }); + + return response()->json($res->all()); + } + } diff --git a/app/Http/Controllers/FollowerController.php b/app/Http/Controllers/FollowerController.php index 113d470cd..f8cec93b5 100644 --- a/app/Http/Controllers/FollowerController.php +++ b/app/Http/Controllers/FollowerController.php @@ -57,6 +57,9 @@ class FollowerController extends Controller 'follower_id' => $user->id, 'following_id' => $target->id ]); + if($remote == true) { + + } } elseif ($isFollowing == 0) { $follower = new Follower(); $follower->profile_id = $user->id; @@ -72,5 +75,6 @@ class FollowerController extends Controller Cache::forget('profile:followers:'.$target->id); Cache::forget('profile:following:'.$user->id); Cache::forget('profile:followers:'.$user->id); + Cache::forget('api:local:exp:rec:'.$user->id); } } diff --git a/app/Http/Controllers/Settings/HomeSettings.php b/app/Http/Controllers/Settings/HomeSettings.php index 2dfa0de38..9b4656bac 100644 --- a/app/Http/Controllers/Settings/HomeSettings.php +++ b/app/Http/Controllers/Settings/HomeSettings.php @@ -41,7 +41,7 @@ trait HomeSettings ]); $changes = false; - $name = strip_tags($request->input('name')); + $name = strip_tags(Purify::clean($request->input('name'))); $bio = $request->filled('bio') ? strip_tags(Purify::clean($request->input('bio'))) : null; $website = $request->input('website'); $email = $request->input('email'); diff --git a/app/Http/Controllers/Settings/LabsSettings.php b/app/Http/Controllers/Settings/LabsSettings.php new file mode 100644 index 000000000..f0020b570 --- /dev/null +++ b/app/Http/Controllers/Settings/LabsSettings.php @@ -0,0 +1,83 @@ +middleware('auth'); + } + + public function labs(Request $request) + { + $profile = $request->user()->profile; + return view('settings.labs', compact('profile')); + } + + public function labsStore(Request $request) + { + $this->validate($request, [ + 'profile_layout' => 'nullable', + 'dark_mode' => 'nullable', + 'profile_suggestions' => 'nullable' + ]); + + $changes = false; + + $profile = $request->user()->profile; + + $cookie = Cookie::forget('dark-mode'); + if($request->has('dark_mode') && $profile->profile_layout != 'moment') { + if($request->dark_mode == 'on') { + $cookie = Cookie::make('dark-mode', true, 43800); + } + } + + if($request->has('profile_layout')) { + if($profile->profile_layout != 'moment') { + $profile->profile_layout = 'moment'; + $changes = true; + } else { + $profile->profile_layout = null; + $changes = true; + } + } else { + if($profile->profile_layout == 'moment') { + $profile->profile_layout = null; + $changes = true; + } + } + + if($request->has('profile_suggestions')) { + if($profile->is_suggestable == false) { + $profile->is_suggestable = true; + $changes = true; + SuggestionService::set($profile->id); + } else { + $profile->is_suggestable = false; + $changes = true; + SuggestionService::del($profile->id); + } + } else { + if($profile->is_suggestable == true) { + $profile->is_suggestable = false; + $changes = true; + SuggestionService::del($profile->id); + } + } + + if($changes == true) { + $profile->save(); + } + + return redirect(route('settings.labs')) + ->with('status', 'Labs preferences successfully updated!') + ->cookie($cookie); + } + +} \ No newline at end of file diff --git a/app/Services/SuggestionService.php b/app/Services/SuggestionService.php new file mode 100644 index 000000000..37a8dff33 --- /dev/null +++ b/app/Services/SuggestionService.php @@ -0,0 +1,49 @@ +whereIsSuggestable(true) + ->whereIsPrivate(false) + ->pluck('id'); + foreach($ids as $id) { + self::set($id); + } + } + } +} \ No newline at end of file diff --git a/config/exp.php b/config/exp.php index 8bd0cf2ab..8101428c3 100644 --- a/config/exp.php +++ b/config/exp.php @@ -2,6 +2,7 @@ return [ - 'lc' => env('EXP_LC', false) + 'lc' => env('EXP_LC', false), + 'rec' => env('EXP_REC', false) ]; \ No newline at end of file diff --git a/database/migrations/2019_04_28_024733_add_suggestions_to_profiles_table.php b/database/migrations/2019_04_28_024733_add_suggestions_to_profiles_table.php new file mode 100644 index 000000000..f5fe2d25e --- /dev/null +++ b/database/migrations/2019_04_28_024733_add_suggestions_to_profiles_table.php @@ -0,0 +1,32 @@ +boolean('is_suggestable')->default(false)->index(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('profiles', function (Blueprint $table) { + $table->dropColumn('is_suggestable'); + }); + } +} diff --git a/public/js/timeline.js b/public/js/timeline.js index f21624fc7..c4269029f 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 261a7d757..ed88cf0bc 100644 Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ diff --git a/resources/assets/js/components/NotificationCard.vue b/resources/assets/js/components/NotificationCard.vue index 65c1fbe18..9c437bc8f 100644 --- a/resources/assets/js/components/NotificationCard.vue +++ b/resources/assets/js/components/NotificationCard.vue @@ -3,16 +3,16 @@

- Notifications + Notifications See All

-
+
Loading...
-
+
diff --git a/resources/assets/js/components/Timeline.vue b/resources/assets/js/components/Timeline.vue index db52aa34a..2071b2795 100644 --- a/resources/assets/js/components/Timeline.vue +++ b/resources/assets/js/components/Timeline.vue @@ -213,10 +213,7 @@

BETA FEATURES

-
- - -
+
Experimental features have been moved to the Labs settings page.
@@ -225,6 +222,31 @@
+
+
+
+
Suggestions For You
+
+
+
+
+ + + +
+

+ + {{rec.username}} + +

+

{{rec.message}}

+
+ Follow +
+
+
+
+
\ No newline at end of file diff --git a/resources/views/settings/template.blade.php b/resources/views/settings/template.blade.php index 3d62a90ca..19656b274 100644 --- a/resources/views/settings/template.blade.php +++ b/resources/views/settings/template.blade.php @@ -1,6 +1,18 @@ @extends('layouts.app') @section('content') +@if (session('status')) +
+ {{ session('status') }} +
+@endif +@if ($errors->any()) +
+ @foreach($errors->all() as $error) +

{{ $error }} + @endforeach +

+@endif
@@ -9,20 +21,6 @@
@include('settings.partial.sidebar')
- @if (session('status')) -
- {{ session('status') }} -
- @endif - @if (session('errors')) -
-
    - @foreach (session('errors') as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif @yield('section')
diff --git a/routes/web.php b/routes/web.php index a7971063f..80dc86e50 100644 --- a/routes/web.php +++ b/routes/web.php @@ -99,6 +99,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::group(['prefix' => 'local'], function () { Route::get('i/follow-suggestions', 'ApiController@followSuggestions'); Route::post('status/compose', 'InternalApiController@compose'); + Route::get('exp/rec', 'ApiController@userRecommendations'); }); }); @@ -231,6 +232,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::post('data-export/account', 'SettingsController@exportAccount')->middleware('dangerzone'); Route::post('data-export/statuses', 'SettingsController@exportStatuses')->middleware('dangerzone'); Route::get('developers', 'SettingsController@developers')->name('settings.developers')->middleware('dangerzone'); + Route::get('labs', 'SettingsController@labs')->name('settings.labs'); + Route::post('labs', 'SettingsController@labsStore'); }); Route::group(['prefix' => 'site'], function () {