mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
* 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>
262 lines
7.4 KiB
Go
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
|
|
}
|