create([
'username' => 'settings_editor',
'name' => 'Settings Editor',
'email' => null,
'password' => Hash::make('secret-strong'),
'status' => 0,
]);
$role = AdminRole::query()->create([
'slug' => 'settings_role',
'name' => 'Settings Role',
]);
$role->syncLegacyPermissionSlugs(['prd.payout.manage']);
$admin->roles()->sync([
(int) $role->id => [
'site_id' => AdminUser::defaultAdminSiteId(),
'granted_at' => now(),
],
]);
return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;
}
function settingsReadOnlyToken(): string
{
$admin = AdminUser::query()->create([
'username' => 'settings_readonly',
'name' => 'Settings Readonly',
'email' => null,
'password' => Hash::make('secret-strong'),
'status' => 0,
]);
$role = AdminRole::query()->create([
'slug' => 'settings_readonly_role',
'name' => 'Settings Readonly Role',
]);
$role->syncLegacyPermissionSlugs(['prd.rebate.manage']);
$admin->roles()->sync([
(int) $role->id => [
'site_id' => AdminUser::defaultAdminSiteId(),
'granted_at' => now(),
],
]);
return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;
}
test('admin can batch update settings in one request', function (): void {
LotterySettings::put('draw.interval_minutes', 5, 'draw');
LotterySettings::put('draw.cooldown_minutes', 15, 'draw');
$token = settingsAdminToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/batch', [
'items' => [
['key' => 'draw.interval_minutes', 'value' => 10],
['key' => 'draw.cooldown_minutes', 'value' => 20],
],
])
->assertOk()
->assertJsonPath('data.items.0.key', 'draw.cooldown_minutes');
expect(LotterySetting::query()->where('setting_key', 'draw.interval_minutes')->value('value_json'))->toBe(10)
->and(LotterySetting::query()->where('setting_key', 'draw.cooldown_minutes')->value('value_json'))->toBe(20);
});
test('admin settings batch update rejects empty items', function (): void {
$token = settingsAdminToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/batch', ['items' => []])
->assertUnprocessable();
});
test('admin can batch update settings with false and empty string values', function (): void {
LotterySettings::put('settlement.auto_run_on_tick', true, 'settlement');
LotterySettings::put('frontend.play_rules_html_zh', '
old
', 'frontend');
$token = settingsAdminToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/batch', [
'items' => [
['key' => 'settlement.auto_run_on_tick', 'value' => false],
['key' => 'frontend.play_rules_html_zh', 'value' => ''],
],
])
->assertOk()
->assertJsonPath('data.items.0.key', 'frontend.play_rules_html_zh')
->assertJsonPath('data.items.0.value', '')
->assertJsonPath('data.items.1.key', 'settlement.auto_run_on_tick')
->assertJsonPath('data.items.1.value', false);
expect(LotterySetting::query()->where('setting_key', 'settlement.auto_run_on_tick')->value('value_json'))->toBeFalse()
->and(LotterySetting::query()->where('setting_key', 'frontend.play_rules_html_zh')->value('value_json'))->toBe('');
});
test('admin can update single setting with false value', function (): void {
LotterySettings::put('settlement.apply_rebate_to_payout', true, 'settlement');
$token = settingsAdminToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/settlement.apply_rebate_to_payout', [
'value' => false,
])
->assertOk()
->assertJsonPath('data.key', 'settlement.apply_rebate_to_payout')
->assertJsonPath('data.value', false);
expect(LotterySetting::query()->where('setting_key', 'settlement.apply_rebate_to_payout')->value('value_json'))->toBeFalse();
});
test('non payout manager cannot batch update settlement settings', function (): void {
LotterySettings::put('settlement.auto_payout_on_tick', true, 'settlement');
$token = settingsReadOnlyToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/batch', [
'items' => [
['key' => 'settlement.auto_payout_on_tick', 'value' => false],
],
])
->assertForbidden();
expect(LotterySetting::query()->where('setting_key', 'settlement.auto_payout_on_tick')->value('value_json'))->toBeTrue();
});
test('non payout manager cannot update single settlement setting', function (): void {
LotterySettings::put('settlement.auto_approve_on_tick', true, 'settlement');
$token = settingsReadOnlyToken();
$this->withHeader('Authorization', 'Bearer '.$token)
->putJson('/api/v1/admin/settings/settlement.auto_approve_on_tick', [
'value' => false,
])
->assertForbidden();
expect(LotterySetting::query()->where('setting_key', 'settlement.auto_approve_on_tick')->value('value_json'))->toBeTrue();
});