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

This commit is contained in:
Daniel Supernault 2023-05-29 03:43:25 -06:00
parent 5154869c8c
commit a2305d5fdc
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
7 changed files with 264 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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,
];
}
}

View file

@ -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);
}
}

View file

@ -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',
]
];
}
}

View file

@ -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');
}
};

View file

@ -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) {