Browse Source

Added `/api/v1.1/accounts/app/settings` endpoint and UserAppSettings model to store app specific settings

Daniel Supernault 2 years ago
parent
commit
a2305d5fdc

+ 48 - 0
app/Http/Controllers/UserAppSettingsController.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Services\Account\AccountAppSettingsService;
+use App\Http\Requests\StoreUserAppSettings;
+use App\Models\UserAppSettings;
+use App\Http\Resources\UserAppSettingsResource;
+
+class UserAppSettingsController extends Controller
+{
+    public function __construct()
+    {
+    	$this->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);
+    }
+}

+ 82 - 0
app/Http/Requests/StoreUserAppSettings.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class StoreUserAppSettings extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        if(!$this->user() || $this->user()->status) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
+     */
+    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);
+    }
+}

+ 27 - 0
app/Http/Resources/UserAppSettingsResource.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class UserAppSettingsResource extends JsonResource
+{
+
+    public static $wrap = null;
+
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    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,
+        ];
+    }
+}

+ 30 - 0
app/Models/UserAppSettings.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use App\User;
+
+class UserAppSettings extends Model
+{
+    use HasFactory;
+
+    protected $guarded = [];
+
+    protected $casts = [
+        'common' => '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);
+    }
+}

+ 43 - 0
app/Services/Account/AccountAppSettingsService.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Services\Account;
+
+use App\Models\UserAppSettings;
+
+class AccountAppSettingsService
+{
+    public static function default()
+    {
+        return [
+            'timelines' => [
+                // 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',
+            ]
+        ];
+    }
+}

+ 31 - 0
database/migrations/2023_05_29_072206_create_user_app_settings_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('user_app_settings', function (Blueprint $table) {
+            $table->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');
+    }
+};

+ 3 - 0
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('two-factor', 'Api\ApiV1Dot1Controller@accountTwoFactor')->middleware($middleware);
 			Route::get('emails-from-pixelfed', 'Api\ApiV1Dot1Controller@accountEmailsFromPixelfed')->middleware($middleware);
 			Route::get('emails-from-pixelfed', 'Api\ApiV1Dot1Controller@accountEmailsFromPixelfed')->middleware($middleware);
 			Route::get('apps-and-applications', 'Api\ApiV1Dot1Controller@accountApps')->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) {
 		Route::group(['prefix' => 'collections'], function () use($middleware) {