feat: complete remaining Go backend modules

This commit is contained in:
zn-admin committed 2026-08-14 00:02:43 +08:00
1 parent cea2751dc5
commit aef5a97165
145 files changed
+18376 -199

No files matched your search

+62 -4
View File
@@ -13,7 +13,20 @@ const organizationColumns = `id, name, status, archive_owner_id, created_at, upd
const ListAdministrationAccountsSQL = `SELECT ` + accountColumns + ` FROM public.platform_users WHERE ($1::text = '' OR organization_id = $1::text) AND ($2::text = '' OR role = $2::text) AND ($3::boolean OR status = 'active') ORDER BY created_at DESC`
const GetAdministrationAccountSQL = `SELECT ` + accountColumns + ` FROM public.platform_users WHERE id = $1::text`
const CreateAdministrationAccountSQL = `INSERT INTO public.platform_users (` + accountColumns + `) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING ` + accountColumns
const UpdateAdministrationAccountSQL = `UPDATE public.platform_users SET phone=$2, display_name=$3, role=$4, organization_id=$5, status=$6, password_hash=$7, password_salt=$8, failed_login_count=$9, locked_until=$10, session_version=$11, last_login_at=$12, legacy_subject=$13, created_at=$14, updated_at=$15 WHERE id=$1::text RETURNING ` + accountColumns
const ApplyAdministrationAccountUpdateSQL = `UPDATE public.platform_users SET
display_name = CASE WHEN $2::boolean THEN $3::text ELSE display_name END,
role = CASE WHEN $4::boolean THEN $5::text ELSE role END,
organization_id = CASE WHEN $6::boolean THEN $7::text ELSE organization_id END,
status = CASE WHEN $8::boolean THEN $9::text ELSE status END,
password_hash = CASE WHEN $10::boolean THEN $11::text ELSE password_hash END,
password_salt = CASE WHEN $10::boolean THEN $12::text ELSE password_salt END,
failed_login_count = CASE WHEN $13::boolean THEN 0 ELSE failed_login_count END,
locked_until = CASE WHEN $13::boolean THEN NULL ELSE locked_until END,
session_version = session_version + CASE WHEN $14::boolean THEN 1 ELSE 0 END,
updated_at = $15::timestamptz
WHERE id = $1::text
AND ($16::text = 'super_admin' OR (role = 'user' AND organization_id = $17::text))
RETURNING ` + accountColumns
const ListAdministrationOrganizationsSQL = `SELECT ` + organizationColumns + ` FROM public.platform_organizations WHERE ($1::boolean OR status = 'active') ORDER BY created_at ASC`
const GetAdministrationOrganizationSQL = `SELECT ` + organizationColumns + ` FROM public.platform_organizations WHERE id = $1::text`
const CreateAdministrationOrganizationSQL = `INSERT INTO public.platform_organizations (` + organizationColumns + `) VALUES ($1,$2,$3,$4,$5,$6) RETURNING ` + organizationColumns
@@ -24,6 +37,7 @@ const ArchiveAssetsSQL = `UPDATE public.assets SET owner_id = $2::text WHERE own
const ArchiveGenerationJobsSQL = `UPDATE public.generation_jobs SET owner_id = $2::text WHERE owner_id = $1::text`
const ArchiveProjectsSQL = `UPDATE public.projects SET owner_id = $2::text WHERE owner_id = $1::text`
const ArchiveImageTemplatesSQL = `UPDATE public.image_templates SET owner_id = $2::text WHERE owner_id = $1::text`
const ArchiveUsageEventsSQL = `UPDATE public.usage_events SET owner_id = $2::text WHERE owner_id = $1::text`
const DeleteAdministrationAccountSQL = `DELETE FROM public.platform_users WHERE id = $1::text`
func (db *Database) administrationQuerier() (Querier, error) {
@@ -71,8 +85,52 @@ func (db *Database) GetAccount(ctx context.Context, id string) (administration.A
func (db *Database) CreateAccount(ctx context.Context, a administration.Account) (administration.Account, error) {
return db.writeAccount(ctx, CreateAdministrationAccountSQL, a)
}
func (db *Database) UpdateAccount(ctx context.Context, a administration.Account) (administration.Account, error) {
return db.writeAccount(ctx, UpdateAdministrationAccountSQL, a)
func (db *Database) UpdateAccount(context.Context, administration.Account) (administration.Account, error) {
return administration.Account{}, fmt.Errorf("full-row account updates are unsafe; use ApplyAccountUpdate")
}
func (db *Database) ApplyAccountUpdate(ctx context.Context, id string, update administration.AccountUpdate) (administration.Account, error) {
q, err := db.administrationQuerier()
if err != nil {
return administration.Account{}, err
}
displayName, hasDisplayName := optionalUpdateValue(update.DisplayName)
role, hasRole := optionalUpdateValue(update.Role)
organizationID, hasOrganizationID := optionalUpdateValue(update.OrganizationID)
status, hasStatus := optionalUpdateValue(update.Status)
passwordHash, passwordSalt, hasPassword := "", "", update.PasswordHash != nil
if hasPassword {
passwordHash, passwordSalt = update.PasswordHash.Hash, update.PasswordHash.Salt
}
rows, err := q.Query(ctx, ApplyAdministrationAccountUpdateSQL,
id,
hasDisplayName, displayName,
hasRole, role,
hasOrganizationID, optionalDatabaseText(organizationID),
hasStatus, status,
hasPassword, passwordHash, passwordSalt,
update.ClearLoginLock, update.IncrementSessionVersion,
update.UpdatedAt,
update.Actor.Role, update.Actor.OrganizationID,
)
if err != nil {
return administration.Account{}, administrationWriteError(err)
}
defer rows.Close()
if !rows.Next() {
if err := rows.Err(); err != nil {
return administration.Account{}, err
}
return administration.Account{}, &administration.Error{Kind: administration.ErrorNotFound, Message: "账号不存在或无权操作。"}
}
return scanAdministrationAccount(rows)
}
func optionalUpdateValue[T any](value *T) (T, bool) {
if value == nil {
var zero T
return zero, false
}
return *value, true
}
func (db *Database) writeAccount(ctx context.Context, statement string, a administration.Account) (administration.Account, error) {
q, e := db.administrationQuerier()
@@ -231,7 +289,7 @@ func (db *Database) DeleteAccount(ctx context.Context, id, archive string) error
_ = tx.Rollback(ctx)
}
}()
for _, statement := range []string{ArchiveAssetsSQL, ArchiveGenerationJobsSQL, ArchiveProjectsSQL, ArchiveImageTemplatesSQL} {
for _, statement := range []string{ArchiveAssetsSQL, ArchiveGenerationJobsSQL, ArchiveProjectsSQL, ArchiveImageTemplatesSQL, ArchiveUsageEventsSQL} {
if e = tx.Exec(ctx, statement, id, archive); e != nil {
return fmt.Errorf("archive account ownership: %w", e)
}