fix: change balance to pointer type
This commit is contained in:
parent
62ccd0ff39
commit
0560340bd4
@ -34,14 +34,14 @@ func NewUserHandler(adminService service.AdminService, concurrencyService *servi
|
||||
|
||||
// CreateUserRequest represents admin create user request
|
||||
type CreateUserRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required,min=6"`
|
||||
Username string `json:"username"`
|
||||
Notes string `json:"notes"`
|
||||
Balance float64 `json:"balance"`
|
||||
Concurrency int `json:"concurrency"`
|
||||
RPMLimit int `json:"rpm_limit"`
|
||||
AllowedGroups []int64 `json:"allowed_groups"`
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required,min=6"`
|
||||
Username string `json:"username"`
|
||||
Notes string `json:"notes"`
|
||||
Balance *float64 `json:"balance"`
|
||||
Concurrency int `json:"concurrency"`
|
||||
RPMLimit int `json:"rpm_limit"`
|
||||
AllowedGroups []int64 `json:"allowed_groups"`
|
||||
}
|
||||
|
||||
// UpdateUserRequest represents admin update user request
|
||||
|
||||
@ -120,7 +120,7 @@ type CreateUserInput struct {
|
||||
Password string
|
||||
Username string
|
||||
Notes string
|
||||
Balance float64
|
||||
Balance *float64
|
||||
Concurrency int
|
||||
RPMLimit int
|
||||
AllowedGroups []int64
|
||||
@ -661,12 +661,19 @@ func (s *adminServiceImpl) GetUser(ctx context.Context, id int64) (*User, error)
|
||||
}
|
||||
|
||||
func (s *adminServiceImpl) CreateUser(ctx context.Context, input *CreateUserInput) (*User, error) {
|
||||
balance := 0.0
|
||||
if input.Balance != nil {
|
||||
balance = *input.Balance
|
||||
} else if s.settingService != nil {
|
||||
balance = s.settingService.GetDefaultBalance(ctx)
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Email: input.Email,
|
||||
Username: input.Username,
|
||||
Notes: input.Notes,
|
||||
Role: RoleUser, // Always create as regular user, never admin
|
||||
Balance: input.Balance,
|
||||
Balance: balance,
|
||||
Concurrency: input.Concurrency,
|
||||
RPMLimit: input.RPMLimit,
|
||||
Status: StatusActive,
|
||||
|
||||
@ -14,13 +14,14 @@ import (
|
||||
func TestAdminService_CreateUser_Success(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 10}
|
||||
svc := &adminServiceImpl{userRepo: repo}
|
||||
balance := 12.5
|
||||
|
||||
input := &CreateUserInput{
|
||||
Email: "user@test.com",
|
||||
Password: "strong-pass",
|
||||
Username: "tester",
|
||||
Notes: "note",
|
||||
Balance: 12.5,
|
||||
Balance: &balance,
|
||||
Concurrency: 7,
|
||||
AllowedGroups: []int64{3, 5},
|
||||
}
|
||||
@ -32,7 +33,7 @@ func TestAdminService_CreateUser_Success(t *testing.T) {
|
||||
require.Equal(t, input.Email, user.Email)
|
||||
require.Equal(t, input.Username, user.Username)
|
||||
require.Equal(t, input.Notes, user.Notes)
|
||||
require.Equal(t, input.Balance, user.Balance)
|
||||
require.Equal(t, balance, user.Balance)
|
||||
require.Equal(t, input.Concurrency, user.Concurrency)
|
||||
require.Equal(t, input.AllowedGroups, user.AllowedGroups)
|
||||
require.Equal(t, RoleUser, user.Role)
|
||||
@ -42,6 +43,56 @@ func TestAdminService_CreateUser_Success(t *testing.T) {
|
||||
require.Equal(t, user, repo.created[0])
|
||||
}
|
||||
|
||||
func TestAdminService_CreateUser_UsesDefaultBalanceWhenBalanceOmitted(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 11}
|
||||
cfg := &config.Config{
|
||||
Default: config.DefaultConfig{
|
||||
UserBalance: 0,
|
||||
},
|
||||
}
|
||||
settingService := NewSettingService(&settingRepoStub{values: map[string]string{
|
||||
SettingKeyDefaultBalance: "0.02",
|
||||
}}, cfg)
|
||||
svc := &adminServiceImpl{userRepo: repo, settingService: settingService}
|
||||
|
||||
user, err := svc.CreateUser(context.Background(), &CreateUserInput{
|
||||
Email: "default-balance@test.com",
|
||||
Password: "strong-pass",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, user)
|
||||
require.Equal(t, 0.02, user.Balance)
|
||||
require.Len(t, repo.created, 1)
|
||||
require.Equal(t, 0.02, repo.created[0].Balance)
|
||||
}
|
||||
|
||||
func TestAdminService_CreateUser_ExplicitZeroBalanceOverridesDefault(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 12}
|
||||
cfg := &config.Config{
|
||||
Default: config.DefaultConfig{
|
||||
UserBalance: 0,
|
||||
},
|
||||
}
|
||||
settingService := NewSettingService(&settingRepoStub{values: map[string]string{
|
||||
SettingKeyDefaultBalance: "0.02",
|
||||
}}, cfg)
|
||||
svc := &adminServiceImpl{userRepo: repo, settingService: settingService}
|
||||
balance := 0.0
|
||||
|
||||
user, err := svc.CreateUser(context.Background(), &CreateUserInput{
|
||||
Email: "zero-balance@test.com",
|
||||
Password: "strong-pass",
|
||||
Balance: &balance,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, user)
|
||||
require.Equal(t, 0.0, user.Balance)
|
||||
require.Len(t, repo.created, 1)
|
||||
require.Equal(t, 0.0, repo.created[0].Balance)
|
||||
}
|
||||
|
||||
func TestAdminService_CreateUser_EmailExists(t *testing.T) {
|
||||
repo := &userRepoStub{createErr: ErrEmailExists}
|
||||
svc := &adminServiceImpl{userRepo: repo}
|
||||
|
||||
@ -115,8 +115,11 @@ export async function getById(id: number): Promise<AdminUser> {
|
||||
export async function create(userData: {
|
||||
email: string
|
||||
password: string
|
||||
username?: string
|
||||
notes?: string
|
||||
balance?: number
|
||||
concurrency?: number
|
||||
rpm_limit?: number
|
||||
allowed_groups?: number[] | null
|
||||
}): Promise<AdminUser> {
|
||||
const { data } = await apiClient.post<AdminUser>('/admin/users', userData)
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.users.columns.balance') }}</label>
|
||||
<input v-model.number="form.balance" type="number" step="any" class="input" />
|
||||
<input v-model="form.balance" type="number" step="any" class="input" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.users.columns.concurrency') }}</label>
|
||||
@ -69,18 +69,24 @@ import Icon from '@/components/icons/Icon.vue'
|
||||
const props = defineProps<{ show: boolean }>()
|
||||
const emit = defineEmits(['close', 'success']); const { t } = useI18n()
|
||||
|
||||
const form = reactive({ email: '', password: '', username: '', notes: '', balance: 0, concurrency: 1, rpm_limit: 0 })
|
||||
const form = reactive({ email: '', password: '', username: '', notes: '', balance: '', concurrency: 1, rpm_limit: 0 })
|
||||
|
||||
const { loading, submit } = useForm({
|
||||
form,
|
||||
submitFn: async (data) => {
|
||||
await adminAPI.users.create(data)
|
||||
const { balance: rawBalance, ...rest } = data
|
||||
const balance = String(rawBalance).trim()
|
||||
const payload: typeof rest & { balance?: number } = { ...rest }
|
||||
if (balance !== '') {
|
||||
payload.balance = Number(balance)
|
||||
}
|
||||
await adminAPI.users.create(payload)
|
||||
emit('success'); emit('close')
|
||||
},
|
||||
successMsg: t('admin.users.userCreated')
|
||||
})
|
||||
|
||||
watch(() => props.show, (v) => { if(v) Object.assign(form, { email: '', password: '', username: '', notes: '', balance: 0, concurrency: 1, rpm_limit: 0 }) })
|
||||
watch(() => props.show, (v) => { if(v) Object.assign(form, { email: '', password: '', username: '', notes: '', balance: '', concurrency: 1, rpm_limit: 0 }) })
|
||||
|
||||
const generateRandomPassword = () => {
|
||||
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$%^&*'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user