Skip to content

Commit

Permalink
feat: many profiles (#5)
Browse files Browse the repository at this point in the history
## Motivation

A person should be able to toggle the account profile for specific
streamers. Thinking on that, we decided to expand for:

- global profile
- per stream profile

This PR adds a hasMany integration for Settings and so on.
  • Loading branch information
danielhe4rt authored Aug 25, 2024
1 parent 7967288 commit a9d7ee5
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 34 deletions.
8 changes: 4 additions & 4 deletions app/Clients/Consumer/ConsumerClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ public function __construct()
]);
}

public function updateUser(User $user): void
public function updateUser(User $user, Settings $settings): void
{
$uri = $this->baseVersionedUrl.'/settings';

/** @var ConnectedAccount $account */
$account = $user->accounts()->where('provider', 'twitch')->first();
/** @var Settings $settings */
$settings = $user->settings()->with(['occupation', 'effect', 'color'])->first();
$account = $user->accounts->first(fn ($account) => $account->provider == 'twitch');

$payload = [
'user_id' => (int) $account->provider_user_id,
'locale' => $settings->locale,
'enabled' => $settings->enabled,
'channel_id' => $settings->channel_id,
'occupation' => [
'name' => $settings->occupation->name,
'translation_key' => $settings->occupation->translation_key,
Expand Down
4 changes: 4 additions & 0 deletions app/DTO/AuthenticationDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public function __construct(

public static function factory(AuthorizationDTO $authorization, User $user): AuthenticationDTO
{
// TODO: remove after releasing the next version. this is a workaround to not break the actual implementation
// of settings feature
$user->settings = $user->settings->first(fn ($settings) => $settings->channel_id = 'global');

return new AuthenticationDTO(
authorization: $authorization,
user: $user,
Expand Down
43 changes: 37 additions & 6 deletions app/Http/Controllers/Api/V1/AuthenticatedUserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,54 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\SettingsRequest;
use App\Models\Settings\Settings;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class AuthenticatedUserController extends Controller
{
public function __construct(private ConsumerClient $client) {}

public function getSettings(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();

$settingsQuery = $user->settings();
$fetcheableSettings = ['global'];

if ($channelId = $request->get('channel_id')) {
$fetcheableSettings[] = $channelId;
}

$response = $settingsQuery->whereIn('channel_id', $fetcheableSettings)
->paginate();

return response()->json($response);
}

public function putSettings(SettingsRequest $request): JsonResponse
{
$validatedSettings = $request->validated();
$userSettings = $request->user()->settings();
$userSettings->update($validatedSettings);

/** @var Settings $response */
$this->client->updateUser($request->user()->refresh());
$request
->user()
->settings()
->updateOrCreate([
'channel_id' => $validatedSettings['channel_id'],
], $validatedSettings);

$response = $userSettings->with(['occupation', 'color', 'effect'])->first();
/** @var User $user */
$user = $request
->user()
->refresh()
->with(['accounts', 'settings.occupation', 'settings.effect', 'settings.color'])
->first();

return response()->json($response);
$settings = $user->settings->first(fn (Settings $settings) => $settings->channel_id == $validatedSettings['channel_id']);

$this->client->updateUser($user, $settings);

return response()->json($settings);
}
}
4 changes: 4 additions & 0 deletions app/Http/Requests/SettingsRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ public function rules(): array

return [
'occupation_id' => ['exists:occupations,id'],
'channel_id' => ['required', 'string'],
'enabled' => ['required'],
'color_id' => ['exists:settings_colors,id'],
'effect_id' => ['exists:settings_effects,id'],
'timezone' => ['string'],
'locale' => ['string'],
'pronouns' => ['string', 'in:'.$acceptedPronouns],
];
}
Expand Down
12 changes: 12 additions & 0 deletions app/Models/Settings/Color.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Models\Settings;

use Database\Factories\ColorFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Color extends Model
{
Expand All @@ -17,4 +19,14 @@ class Color extends Model
'translation_key',
'hex',
];

public function settings(): HasMany
{
return $this->hasMany(Settings::class);
}

protected static function newFactory(): ColorFactory
{
return ColorFactory::new();
}
}
12 changes: 12 additions & 0 deletions app/Models/Settings/Effect.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Models\Settings;

use Database\Factories\EffectFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Effect extends Model
{
Expand All @@ -18,4 +20,14 @@ class Effect extends Model
'class_name',
'hex',
];

public function settings(): HasMany
{
return $this->hasMany(Settings::class);
}

protected static function newFactory(): EffectFactory
{
return EffectFactory::new();
}
}
15 changes: 15 additions & 0 deletions app/Models/Settings/Occupation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

namespace App\Models\Settings;

use Database\Factories\OccupationFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Occupation extends Model
{
use HasFactory;

protected $fillable = ['name', 'slug', 'translation_key'];

public function getImageUrlAttribute(): string
Expand All @@ -16,4 +21,14 @@ public function getImageUrlAttribute(): string
protected $appends = [
'image_url',
];

public function settings(): HasMany
{
return $this->hasMany(Settings::class);
}

protected static function newFactory(): OccupationFactory
{
return OccupationFactory::new();
}
}
13 changes: 13 additions & 0 deletions app/Models/Settings/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
namespace App\Models\Settings;

use App\Models\User;
use Database\Factories\SettingsFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
* @property string $channel_id
* @property bool $enabled
*/
class Settings extends Model
{
use HasFactory;

protected $fillable = [
'user_id',
'enabled',
'channel_id',
'color_id',
'effect_id',
'occupation_id',
Expand All @@ -24,6 +31,7 @@ class Settings extends Model

protected $casts = [
'is_developer' => 'boolean',
'enabled' => 'boolean',
];

public function getPronounsAttribute(): array
Expand All @@ -50,4 +58,9 @@ public function effect(): BelongsTo
{
return $this->belongsTo(Effect::class);
}

protected static function newFactory(): SettingsFactory
{
return SettingsFactory::new();
}
}
5 changes: 2 additions & 3 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
Expand Down Expand Up @@ -81,8 +80,8 @@ public function accounts(): HasMany
return $this->hasMany(ConnectedAccount::class);
}

public function settings(): HasOne
public function settings(): HasMany
{
return $this->hasOne(Settings::class);
return $this->hasMany(Settings::class);
}
}
1 change: 1 addition & 0 deletions app/Observers/UserObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function created(User $user): void

$user->settings()->create([
'occupation_id' => 1, // none
'channel_id' => 'global',
'color_id' => 1, // none
'effect_id' => 1, // none
'pronouns' => 'none', // none
Expand Down
2 changes: 1 addition & 1 deletion database/factories/EffectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function definition(): array
'name' => $this->faker->name(),
'slug' => $this->faker->slug(),
'translation_key' => $this->faker->word(),
'class' => $this->faker->word(),
'class_name' => $this->faker->word(),
'hex' => $this->faker->word(),
];
}
Expand Down
20 changes: 20 additions & 0 deletions database/factories/OccupationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Database\Factories;

use App\Models\Settings\Occupation;
use Illuminate\Database\Eloquent\Factories\Factory;

class OccupationFactory extends Factory
{
protected $model = Occupation::class;

public function definition(): array
{
return [
'name' => $this->faker->name,
'slug' => $this->faker->name,
'translation_key' => $this->faker->name,
];
}
}
20 changes: 15 additions & 5 deletions database/factories/SettingsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Database\Factories;

use App\Models\Settings\Color;
use App\Models\Settings\Effect;
use App\Models\Settings\Occupation;
use App\Models\Settings\Settings;
use App\Models\User;
Expand All @@ -12,15 +14,23 @@ class SettingsFactory extends Factory
{
protected $model = Settings::class;

public function definition()
public function definition(): array
{
return [
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
'pronouns' => $this->faker->word(),
$pronouns = collect(config('extension.pronouns'))->keys()->shuffle()->first();

return [
'user_id' => User::factory(),
'channel_id' => 'global',
'enabled' => true,
'color_id' => Color::factory(),
'effect_id' => Effect::factory(),
'occupation_id' => Occupation::factory(),
'pronouns' => $pronouns,
'timezone' => $this->faker->timezone,
'locale' => $this->faker->locale(),
'is_developer' => false,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
}
}
10 changes: 6 additions & 4 deletions database/migrations/2024_08_10_210719_create_settings_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ public function up()
$table->id();
$table->foreignId('user_id')->constrained('users');
$table->foreignId('occupation_id')->constrained('occupations');
$table->string('pronouns');
$table->string('timezone');
$table->string('locale');
$table->boolean('enabled')->default(true);
$table->string('channel_id')->default('global');
$table->string('pronouns')->nullable();
$table->string('timezone')->nullable();
$table->string('locale')->nullable();
$table->boolean('is_developer')->default(false);
$table->timestamps();
});
}

public function down()
public function down(): void
{
Schema::dropIfExists('settings');
}
Expand Down
4 changes: 2 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="DB_DATABASE" value="dev_test"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
Expand Down
2 changes: 2 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
Route::post('/authenticate/{provider}', [OAuthController::class, 'authenticateWithOAuth']);

Route::middleware(['auth:sanctum', 'throttle:30,1'])->group(function () {
Route::get('/me/settings', [AuthenticatedUserController::class, 'getSettings'])
->name('auth.my-settings');
Route::put('/me/update-settings', [AuthenticatedUserController::class, 'putSettings'])
->name('auth.update-settings');
});
Expand Down
Loading

0 comments on commit a9d7ee5

Please sign in to comment.