From a2305d5fdccd7f252ef452de517eb9b9297d0f42 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 29 May 2023 03:43:25 -0600 Subject: [PATCH 1/2] Added `/api/v1.1/accounts/app/settings` endpoint and UserAppSettings model to store app specific settings --- .../Controllers/UserAppSettingsController.php | 48 +++++++++++ app/Http/Requests/StoreUserAppSettings.php | 82 +++++++++++++++++++ .../Resources/UserAppSettingsResource.php | 27 ++++++ app/Models/UserAppSettings.php | 30 +++++++ .../Account/AccountAppSettingsService.php | 43 ++++++++++ ..._072206_create_user_app_settings_table.php | 31 +++++++ routes/api.php | 3 + 7 files changed, 264 insertions(+) create mode 100644 app/Http/Controllers/UserAppSettingsController.php create mode 100644 app/Http/Requests/StoreUserAppSettings.php create mode 100644 app/Http/Resources/UserAppSettingsResource.php create mode 100644 app/Models/UserAppSettings.php create mode 100644 app/Services/Account/AccountAppSettingsService.php create mode 100644 database/migrations/2023_05_29_072206_create_user_app_settings_table.php diff --git a/app/Http/Controllers/UserAppSettingsController.php b/app/Http/Controllers/UserAppSettingsController.php new file mode 100644 index 000000000..b18c97931 --- /dev/null +++ b/app/Http/Controllers/UserAppSettingsController.php @@ -0,0 +1,48 @@ +middleware('auth'); + } + + public function get(Request $request) + { + abort_if(!$request->user(), 403); + + $settings = UserAppSettings::whereUserId($request->user()->id)->first(); + + if(!$settings) { + return [ + 'id' => (string) $request->user()->profile_id, + 'username' => $request->user()->username, + 'updated_at' => null, + 'common' => AccountAppSettingsService::default(), + ]; + } + + return new UserAppSettingsResource($settings); + } + + public function store(StoreUserAppSettings $request) + { + $res = UserAppSettings::updateOrCreate([ + 'user_id' => $request->user()->id, + ],[ + 'profile_id' => $request->user()->profile_id, + 'common' => $request->common, + ] + ); + + return new UserAppSettingsResource($res); + } +} diff --git a/app/Http/Requests/StoreUserAppSettings.php b/app/Http/Requests/StoreUserAppSettings.php new file mode 100644 index 000000000..424ef4931 --- /dev/null +++ b/app/Http/Requests/StoreUserAppSettings.php @@ -0,0 +1,82 @@ +user() || $this->user()->status) { + return false; + } + + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules(): array + { + return [ + 'common' => 'required|array', + 'common.timelines.show_public' => 'required|boolean', + 'common.timelines.show_network' => 'required|boolean', + 'common.timelines.hide_likes_shares' => 'required|boolean', + 'common.media.hide_public_behind_cw' => 'required|boolean', + 'common.media.always_show_cw' => 'required|boolean', + 'common.media.show_alt_text' => 'required|boolean', + 'common.appearance.links_use_in_app_browser' => 'required|boolean', + 'common.appearance.theme' => 'required|string|in:light,dark,system', + ]; + } + /** + * Prepare inputs for validation. + * + * @return void + */ + protected function prepareForValidation() + { + $this->merge([ + 'common' => array_merge( + $this->input('common'), + [ + 'timelines' => [ + 'show_public' => $this->toBoolean($this->input('common.timelines.show_public')), + 'show_network' => $this->toBoolean($this->input('common.timelines.show_network')), + 'hide_likes_shares' => $this->toBoolean($this->input('common.timelines.hide_likes_shares')) + ], + + 'media' => [ + 'hide_public_behind_cw' => $this->toBoolean($this->input('common.media.hide_public_behind_cw')), + 'always_show_cw' => $this->toBoolean($this->input('common.media.always_show_cw')), + 'show_alt_text' => $this->toBoolean($this->input('common.media.show_alt_text')), + ], + + 'appearance' => [ + 'links_use_in_app_browser' => $this->toBoolean($this->input('common.appearance.links_use_in_app_browser')), + 'theme' => $this->input('common.appearance.theme'), + ] + ] + ) + ]); + } + + /** + * Convert to boolean + * + * @param $booleable + * @return boolean + */ + private function toBoolean($booleable) + { + return filter_var($booleable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + } +} diff --git a/app/Http/Resources/UserAppSettingsResource.php b/app/Http/Resources/UserAppSettingsResource.php new file mode 100644 index 000000000..814a8f55c --- /dev/null +++ b/app/Http/Resources/UserAppSettingsResource.php @@ -0,0 +1,27 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => (string) $this->profile_id, + 'username' => $request->user()->username, + 'updated_at' => str_replace('+00:00', 'Z', $this->updated_at->format(DATE_RFC3339_EXTENDED)), + 'common' => $this->common, + ]; + } +} diff --git a/app/Models/UserAppSettings.php b/app/Models/UserAppSettings.php new file mode 100644 index 000000000..aa0f7f351 --- /dev/null +++ b/app/Models/UserAppSettings.php @@ -0,0 +1,30 @@ + 'json', + 'custom' => 'json', + 'common.timelines.show_public' => 'boolean', + 'common.timelines.show_network' => 'boolean', + 'common.timelines.hide_likes_shares' => 'boolean', + 'common.media.hide_public_behind_cw' => 'boolean', + 'common.media.always_show_cw' => 'boolean', + 'common.media.show_alt_text' => 'boolean', + ]; + + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Services/Account/AccountAppSettingsService.php b/app/Services/Account/AccountAppSettingsService.php new file mode 100644 index 000000000..a8107faac --- /dev/null +++ b/app/Services/Account/AccountAppSettingsService.php @@ -0,0 +1,43 @@ + [ + // Show public timeline feed + 'show_public' => false, + + // Show network timeline feed + 'show_network' => false, + + // Hide likes and share counts + 'hide_likes_shares' => false, + ], + + 'media' => [ + // Hide media on Public/Network timelines behind CW + 'hide_public_behind_cw' => true, + + // Always show media with CW + 'always_show_cw' => false, + + // Show alt text if present below media + 'show_alt_text' => false, + ], + + 'appearance' => [ + // Use in-app browser when opening links + 'links_use_in_app_browser' => true, + + // App theme, can be 'light', 'dark' or 'system' + 'theme' => 'system', + ] + ]; + } +} diff --git a/database/migrations/2023_05_29_072206_create_user_app_settings_table.php b/database/migrations/2023_05_29_072206_create_user_app_settings_table.php new file mode 100644 index 000000000..813ae4603 --- /dev/null +++ b/database/migrations/2023_05_29_072206_create_user_app_settings_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedInteger('user_id')->unique()->index(); + $table->bigInteger('profile_id')->unsigned()->unique()->index(); + $table->json('common')->nullable(); + $table->json('custom')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('user_app_settings'); + } +}; diff --git a/routes/api.php b/routes/api.php index a0b8b5155..ba883073e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -117,6 +117,9 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::get('two-factor', 'Api\ApiV1Dot1Controller@accountTwoFactor')->middleware($middleware); Route::get('emails-from-pixelfed', 'Api\ApiV1Dot1Controller@accountEmailsFromPixelfed')->middleware($middleware); Route::get('apps-and-applications', 'Api\ApiV1Dot1Controller@accountApps')->middleware($middleware); + + Route::get('app/settings', 'UserAppSettingsController@get')->middleware($middleware); + Route::post('app/settings', 'UserAppSettingsController@store')->middleware($middleware); }); Route::group(['prefix' => 'collections'], function () use($middleware) { From cd08348f4ce1821fafe0524598d8e130c2704800 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 29 May 2023 03:48:59 -0600 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6e6e348..6fe9e5bf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### API Changes - Added `following_since` attribute to `/api/v1/accounts/relationships` endpoint when `_pe=1` (pixelfed entity) parameter is present ([992d910b](https://github.com/pixelfed/pixelfed/commit/992d910b)) +- Added `/api/v1.1/accounts/app/settings` endpoint and UserAppSettings model to store app specific settings ([a2305d5f](https://github.com/pixelfed/pixelfed/commit/a2305d5f)) ### Updates - Update StatusService, fix bug in getFull method ([4d8b4dcf](https://github.com/pixelfed/pixelfed/commit/4d8b4dcf)) @@ -17,7 +18,6 @@ - Update UpdateStatusService, fix formatting issue. Fixes #4423 ([4479055e](https://github.com/pixelfed/pixelfed/commit/4479055e)) - Update nginx config ([ee3b6e09](https://github.com/pixelfed/pixelfed/commit/ee3b6e09)) - Update Status model, increase max mentions, hashtags and links ([1430f532](https://github.com/pixelfed/pixelfed/commit/1430f532)) -- ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.7 (2023-05-24)](https://github.com/pixelfed/pixelfed/compare/v0.11.6...v0.11.7) @@ -1102,7 +1102,7 @@ - Added post embeds ([1fecf717](https://github.com/pixelfed/pixelfed/commit/1fecf717)) - Added profile embeds ([fb7a3cf0](https://github.com/pixelfed/pixelfed/commit/fb7a3cf0)) - Added Force MetroUI labs experiment ([#1889](https://github.com/pixelfed/pixelfed/pull/1889)) -- Added Stories, to enable add ```STORIES_ENABLED=true``` to ```.env``` and run ```php artisan config:cache && php artisan cache:clear```. If opcache is enabled you may need to reload the web server. +- Added Stories, to enable add ```STORIES_ENABLED=true``` to ```.env``` and run ```php artisan config:cache && php artisan cache:clear```. If opcache is enabled you may need to reload the web server. ### Fixed - Fixed like and share/reblog count on profiles ([86cb7d09](https://github.com/pixelfed/pixelfed/commit/86cb7d09))