Expand profile gender options and cover country plus activity persistence.
Allow the broader gender enum and add tests for country saves and discovery event recording.
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (! Schema::hasTable('user_profiles') || ! Schema::hasColumn('user_profiles', 'gender')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$driver = Schema::getConnection()->getDriverName();
|
||||||
|
|
||||||
|
if ($driver !== 'mysql') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Production/local imports may still be enum('M','F') while the app stores X
|
||||||
|
// for "prefer not to say" / non-binary. Expand safely without rewriting rows.
|
||||||
|
DB::statement("ALTER TABLE `user_profiles` MODIFY `gender` ENUM('M','F','X') NULL DEFAULT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if (! Schema::hasTable('user_profiles') || ! Schema::hasColumn('user_profiles', 'gender')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$driver = Schema::getConnection()->getDriverName();
|
||||||
|
|
||||||
|
if ($driver !== 'mysql') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map unsupported values before shrinking the enum.
|
||||||
|
DB::table('user_profiles')
|
||||||
|
->where('gender', 'X')
|
||||||
|
->update(['gender' => null]);
|
||||||
|
|
||||||
|
DB::statement("ALTER TABLE `user_profiles` MODIFY `gender` ENUM('M','F') NULL DEFAULT NULL");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,6 +30,25 @@ it('stores a selected country on the personal settings endpoint', function (): v
|
|||||||
|
|
||||||
expect($user->country_id)->toBe($country->id);
|
expect($user->country_id)->toBe($country->id);
|
||||||
expect(optional($user->profile)->country_code)->toBe('SI');
|
expect(optional($user->profile)->country_code)->toBe('SI');
|
||||||
|
expect(optional($user->profile)->gender)->toBe('M');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stores prefer-not-to-say gender as X on the personal settings endpoint', function (): void {
|
||||||
|
$this->withoutMiddleware(ForumBotProtectionMiddleware::class);
|
||||||
|
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
$response = $this->actingAs($user)->postJson('/settings/personal/update', [
|
||||||
|
'birthday' => '1991-05-10',
|
||||||
|
'gender' => 'x',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
|
||||||
|
$user->refresh();
|
||||||
|
|
||||||
|
expect(optional($user->profile)->gender)->toBe('X');
|
||||||
|
expect(optional($user->profile)->birthdate?->toDateString())->toBe('1991-05-10');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects invalid country identifiers on the personal settings endpoint', function (): void {
|
it('rejects invalid country identifiers on the personal settings endpoint', function (): void {
|
||||||
|
|||||||
@@ -136,3 +136,49 @@ it('following tab shows only events from followed users', function () {
|
|||||||
expect($events)->toHaveCount(1);
|
expect($events)->toHaveCount(1);
|
||||||
expect(data_get($events->first(), 'user.id'))->toBe($creator->id);
|
expect(data_get($events->first(), 'user.id'))->toBe($creator->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('comments and replies feeds do not query unrelated activity sources', function () {
|
||||||
|
foreach (['comments', 'replies'] as $filter) {
|
||||||
|
DB::flushQueryLog();
|
||||||
|
DB::enableQueryLog();
|
||||||
|
|
||||||
|
$this->getJson('/api/activity?filter=' . $filter)
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('filter', $filter);
|
||||||
|
|
||||||
|
$sql = collect(DB::getQueryLog())
|
||||||
|
->pluck('query')
|
||||||
|
->map(fn (string $query): string => strtolower($query))
|
||||||
|
->implode("\n");
|
||||||
|
|
||||||
|
expect($sql)
|
||||||
|
->not->toContain('activity_events')
|
||||||
|
->not->toContain('comment_reactions')
|
||||||
|
->not->toContain('user_mentions');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('my activity feed keeps only the authenticated actor activity', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$other = User::factory()->create();
|
||||||
|
$artwork = Artwork::factory()->create();
|
||||||
|
|
||||||
|
ActivityEvent::record($user->id, ActivityEvent::TYPE_UPLOAD, ActivityEvent::TARGET_ARTWORK, $artwork->id);
|
||||||
|
ActivityEvent::record($other->id, ActivityEvent::TYPE_UPLOAD, ActivityEvent::TARGET_ARTWORK, $artwork->id);
|
||||||
|
|
||||||
|
$response = $this->actingAs($user)->getJson('/api/activity?filter=my');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
expect(collect($response->json('data')))
|
||||||
|
->toHaveCount(1)
|
||||||
|
->and(data_get($response->json('data.0'), 'user.id'))->toBe($user->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('guest activity feed is capped to the latest page', function () {
|
||||||
|
$response = $this->getJson('/api/activity?page=2&per_page=50');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
expect($response->json('meta.current_page'))->toBe(1)
|
||||||
|
->and($response->json('meta.per_page'))->toBe(20)
|
||||||
|
->and(count($response->json('data')))->toBeLessThanOrEqual(20);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user