Files
OwnCord/Server/db/dbgen/users.sql.go
T
J3vbandClaude Fable 5 7be9ccd2f9 fix: batch of 22 correctness fixes across server and client (#1371)
* fix(voice): 4 defect(s) (OC-0008, OC-0009, OC-0042, OC-0080)

Guard LiveKit session state against supersession: bump the camera/screen
generation in leaveVoice and teardownForReconnect so an in-flight enable
discards its track, bail out of restoreLocalVoiceState when a newer room
claimed _room mid-await, and recheck isStateConnected in the auto-reconnect
tail.

* fix(ws): 1 defect(s) (OC-0019)

* fix(db): 1 defect(s) (OC-0023)

* fix(ws): 1 defect(s) (OC-0029)

* fix(ws): 1 defect(s) (OC-0032)

* fix(voice): 1 defect(s) (OC-0034)

* fix(admin): 1 defect(s) (OC-0035)

* fix(service): 2 defect(s) (OC-0036, OC-0128)

* fix(voice): 2 defect(s) (OC-0038, OC-0065)

OC-0038: the LiveKit participant_left webhook cleared the leaver's own
client voice state before broadcasting voice_leave, so the broadcast
audience (READ_MESSAGES holders union still-in-the-room participants)
could no longer see them. Voice membership is gated on CONNECT_VOICE
alone, so a participant without READ_MESSAGES never learned the server
had torn down their call. Extracted finishVoiceLeave's audience logic
into broadcastVoiceEventWithLeaver and used it on the webhook path.

OC-0065: handleWebhookParticipantJoined OR'd a GetVoiceState read error
into the same branch as "no matching row", so a transient DB failure
ejected a legitimate participant from the SFU mid-call. Now the read
error is logged and the check skipped, matching sweepStaleVoiceStates.

* fix(client): 1 defect(s) (OC-0041)

* fix(client): 1 defect(s) (OC-0043)

* fix(client): 1 defect(s) (OC-0046)

* fix(client): 1 defect(s) (OC-0047)

* fix(client): 1 defect(s) (OC-0049)

* fix(client): 1 defect(s) (OC-0108)

* fix(client): 2 defect(s) (OC-0111, OC-0143)

OC-0111: retry a presence_update dropped by the 1-per-10s limiter once the
window reopens, so auto-idle's return-to-online does not leave the server
and every other client stuck on idle.

OC-0143: pass apiConfig.host to the DM profile sidebar so per-user notes
are scoped per server, matching channel mutes, the NSFW gate and volume.

* test(ws): align aborted-switch test with OC-0034 no-resurrect behavior

The fix agent rewrote this pre-existing test (it locked the buggy restore
path) but the prove agent left it out of c67d25ed; committed state alone
failed go test ./ws/ without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 16:15:32 +02:00

262 lines
7.4 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: users.sql
package dbgen
import (
"context"
"database/sql"
)
const banUser = `-- name: BanUser :exec
UPDATE users SET banned = 1, ban_reason = ?, ban_expires = ? WHERE id = ?
`
type BanUserParams struct {
BanReason *string `json:"banReason"`
BanExpires *string `json:"banExpires"`
ID int64 `json:"id"`
}
func (q *Queries) BanUser(ctx context.Context, arg BanUserParams) error {
_, err := q.db.ExecContext(ctx, banUser, arg.BanReason, arg.BanExpires, arg.ID)
return err
}
const countUsers = `-- name: CountUsers :one
SELECT COUNT(*) FROM users
`
func (q *Queries) CountUsers(ctx context.Context) (int64, error) {
row := q.db.QueryRowContext(ctx, countUsers)
var count int64
err := row.Scan(&count)
return count, err
}
const countUsersWithoutTOTP = `-- name: CountUsersWithoutTOTP :one
SELECT COUNT(*) FROM users WHERE banned = 0 AND totp_secret IS NULL
`
func (q *Queries) CountUsersWithoutTOTP(ctx context.Context) (int64, error) {
row := q.db.QueryRowContext(ctx, countUsersWithoutTOTP)
var count int64
err := row.Scan(&count)
return count, err
}
const createUser = `-- name: CreateUser :execresult
INSERT INTO users (username, password, role_id) VALUES (?, ?, ?)
`
type CreateUserParams struct {
Username string `json:"username"`
Password string `json:"password"`
RoleID int64 `json:"roleId"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (sql.Result, error) {
return q.db.ExecContext(ctx, createUser, arg.Username, arg.Password, arg.RoleID)
}
const getUserByID = `-- name: GetUserByID :one
SELECT id, username, password, avatar, role_id, totp_secret, status,
created_at, last_seen, banned, ban_reason, ban_expires, identity_public_key,
display_name, about, custom_status
FROM users WHERE id = ?
`
func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
row := q.db.QueryRowContext(ctx, getUserByID, id)
var i User
err := row.Scan(
&i.ID,
&i.Username,
&i.Password,
&i.Avatar,
&i.RoleID,
&i.TotpSecret,
&i.Status,
&i.CreatedAt,
&i.LastSeen,
&i.Banned,
&i.BanReason,
&i.BanExpires,
&i.IdentityPublicKey,
&i.DisplayName,
&i.About,
&i.CustomStatus,
)
return i, err
}
const getUserByUsername = `-- name: GetUserByUsername :one
SELECT id, username, password, avatar, role_id, totp_secret, status,
created_at, last_seen, banned, ban_reason, ban_expires, identity_public_key,
display_name, about, custom_status
FROM users WHERE username = ? COLLATE NOCASE
`
func (q *Queries) GetUserByUsername(ctx context.Context, username string) (User, error) {
row := q.db.QueryRowContext(ctx, getUserByUsername, username)
var i User
err := row.Scan(
&i.ID,
&i.Username,
&i.Password,
&i.Avatar,
&i.RoleID,
&i.TotpSecret,
&i.Status,
&i.CreatedAt,
&i.LastSeen,
&i.Banned,
&i.BanReason,
&i.BanExpires,
&i.IdentityPublicKey,
&i.DisplayName,
&i.About,
&i.CustomStatus,
)
return i, err
}
const listMembers = `-- name: ListMembers :many
SELECT u.id, u.username, u.avatar, u.status, LOWER(r.name), u.identity_public_key,
u.display_name, u.custom_status
FROM users u
JOIN roles r ON u.role_id = r.id
WHERE (u.banned = 0 OR (u.ban_expires IS NOT NULL AND replace(u.ban_expires, ' ', 'T') <= strftime('%Y-%m-%dT%H:%M:%SZ', 'now')))
ORDER BY u.username ASC
`
type ListMembersRow struct {
ID int64 `json:"id"`
Username string `json:"username"`
Avatar *string `json:"avatar"`
Status string `json:"status"`
Lower string `json:"lower"`
IdentityPublicKey *string `json:"identityPublicKey"`
DisplayName *string `json:"displayName"`
CustomStatus *string `json:"customStatus"`
}
// The ready payload's member roster. docs/protocol.md documents members[] as
// "All registered users", so this must not silently truncate: the previous
// LIMIT 1000 dropped every member past the first thousand with no has_more
// signal, leaving those users unrenderable and unmentionable on the client
// with nothing to indicate the list was incomplete.
func (q *Queries) ListMembers(ctx context.Context) ([]ListMembersRow, error) {
rows, err := q.db.QueryContext(ctx, listMembers)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMembersRow{}
for rows.Next() {
var i ListMembersRow
if err := rows.Scan(
&i.ID,
&i.Username,
&i.Avatar,
&i.Status,
&i.Lower,
&i.IdentityPublicKey,
&i.DisplayName,
&i.CustomStatus,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markUserDisconnected = `-- name: MarkUserDisconnected :exec
UPDATE users
SET status = CASE WHEN status = 'online' THEN 'offline' ELSE status END,
last_seen = datetime('now')
WHERE id = ?
`
// Disconnect bookkeeping. It clears only 'online', which is the one status
// that means "has a live session"; idle, dnd and invisible are choices the
// user made and are what the next connect reads instead of stamping online
// (db.ConnectStatus). A stale choice never renders as "present" because the
// read path treats a member with no live connection as offline regardless.
func (q *Queries) MarkUserDisconnected(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, markUserDisconnected, id)
return err
}
const resetAllUserStatuses = `-- name: ResetAllUserStatuses :exec
UPDATE users SET status = 'offline' WHERE status = 'online'
`
// Startup reset: nothing is connected yet, so every 'online' is a leftover
// from the previous process. Chosen statuses survive for the same reason they
// survive a disconnect.
func (q *Queries) ResetAllUserStatuses(ctx context.Context) error {
_, err := q.db.ExecContext(ctx, resetAllUserStatuses)
return err
}
const unbanUser = `-- name: UnbanUser :exec
UPDATE users SET banned = 0, ban_reason = NULL, ban_expires = NULL WHERE id = ?
`
func (q *Queries) UnbanUser(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, unbanUser, id)
return err
}
const updateUserIdentityKey = `-- name: UpdateUserIdentityKey :exec
UPDATE users SET identity_public_key = ? WHERE id = ?
`
type UpdateUserIdentityKeyParams struct {
IdentityPublicKey *string `json:"identityPublicKey"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserIdentityKey(ctx context.Context, arg UpdateUserIdentityKeyParams) error {
_, err := q.db.ExecContext(ctx, updateUserIdentityKey, arg.IdentityPublicKey, arg.ID)
return err
}
const updateUserStatus = `-- name: UpdateUserStatus :exec
UPDATE users SET status = ?, last_seen = datetime('now') WHERE id = ?
`
type UpdateUserStatusParams struct {
Status string `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) error {
_, err := q.db.ExecContext(ctx, updateUserStatus, arg.Status, arg.ID)
return err
}
const updateUserTOTPSecret = `-- name: UpdateUserTOTPSecret :exec
UPDATE users SET totp_secret = ? WHERE id = ?
`
type UpdateUserTOTPSecretParams struct {
TotpSecret *string `json:"totpSecret"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserTOTPSecret(ctx context.Context, arg UpdateUserTOTPSecretParams) error {
_, err := q.db.ExecContext(ctx, updateUserTOTPSecret, arg.TotpSecret, arg.ID)
return err
}