Files
OwnCord/Server/db/dbgen/querier.go
T
J3vbandClaude Fable 5 c86d803a18 fix: resolve the six blocked batch-4 ledger findings (#1393)
* fix(ws): resolve an empty READ audience for a channel whose row is gone

channelReadAudience already failed closed on a GetChannel error; a
deleted channel returns (nil, nil) and fell through to the role scan.
Return nobody for a missing row too — voice teardown callers union the
room's participants and the leaver back in, so their signals still land.

Test locks both halves: the non-participant hears nothing, the leaver
still gets voice_leave. (OC-0090)

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

* fix(ws): re-elect the key holder in CleanupVoiceForChannel

Every other voice-removal path re-elects (finishVoiceLeave, the LiveKit
webhook, registerNow, rollbackVoiceJoin, sweepStaleVoiceStates); the
channel delete/archive path did not, so a torn-down channel's
voiceKeyHolders entry lived for the process lifetime. One updateKeyHolder
call at the end of the teardown deletes it. (OC-0012)

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

* fix(ws): implement BroadcastMemberUnban so unban reaches connected clients

The admin unban path reaches the hub through an optional-capability type
assertion that *ws.Hub never satisfied, so it always missed silently and
clients connected during a ban kept the user missing from their member
store. Implement the mirror of BroadcastMemberBan: fan out the same
member_join a fresh connect sends (clients already map it to addMember),
reporting offline since the unbanned user cannot be connected. A
compile-time assertion in admin pins the wiring so the assertion can
never silently miss again. (OC-0058)

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

* fix(db): exclude the requester's own flag from the video-cap stream count

EnableCameraIfUnderLimit and EnableScreenshareIfUnderLimit counted every
stream in the channel including the very flag the UPDATE sets, so a user
whose server-side flag was already 1 (client lost track and retried) was
refused at the cap against their own stream, with no path out. Subtract
the outer row's own bit from the correlated count: re-enable becomes
idempotent while the requester's other stream and everyone else's still
count. sqlc layer regenerated. (OC-0081)

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

* chore(ledger): resolve the six blocked batch-4 findings

Four fixed in this branch (OC-0012, OC-0058, OC-0081, OC-0090), each
with an independent revert-proof pass. Two were already fixed on main by
later sibling fixes and are recorded as such: OC-0086 by the OC-0017
pre-delete re-check (#1374), OC-0101 by the OC-0206 early watermark bump
(#1375). The ledger holds zero open and zero blocked findings.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 18:28:00 +02:00

277 lines
19 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package dbgen
import (
"context"
"database/sql"
"time"
)
type Querier interface {
AddReaction(ctx context.Context, arg AddReactionParams) error
AdminUpdateChannel(ctx context.Context, arg AdminUpdateChannelParams) error
ApplyVoiceServerDeafen(ctx context.Context, arg ApplyVoiceServerDeafenParams) (sql.Result, error)
// Scoped to channel_id as well as user_id: the moderator's authorization is
// checked against a channel snapshot several round trips before this write
// lands, so an unscoped `WHERE user_id = ?` would follow the target onto
// whatever channel their row points at by then -- including a DM call the
// moderator was never authorized against (OC-0005). :execresult so the
// caller can tell a real no-op (target moved) from a normal apply.
ApplyVoiceServerMute(ctx context.Context, arg ApplyVoiceServerMuteParams) (sql.Result, error)
BanUser(ctx context.Context, arg BanUserParams) error
BlockUser(ctx context.Context, arg BlockUserParams) error
CleanupExpiredLockouts(ctx context.Context, expiresAt string) error
ClearAllVoiceStates(ctx context.Context) error
ClearVoiceServerDeafen(ctx context.Context, arg ClearVoiceServerDeafenParams) (sql.Result, error)
ClearVoiceServerMute(ctx context.Context, arg ClearVoiceServerMuteParams) (sql.Result, error)
ClearVoiceState(ctx context.Context, userID int64) error
CloseDM(ctx context.Context, arg CloseDMParams) error
CountActiveCameras(ctx context.Context, channelID int64) (int64, error)
CountActiveInvites(ctx context.Context) (int64, error)
CountActiveMessages(ctx context.Context) (int64, error)
CountChannels(ctx context.Context) (int64, error)
CountDMParticipants(ctx context.Context, channelID int64) (int64, error)
CountRoleMembers(ctx context.Context) ([]CountRoleMembersRow, error)
CountUsers(ctx context.Context) (int64, error)
// Authorization probe for the file route: an unlinked attachment is readable by
// everyone exactly while some user's avatar points at it. Covered by the
// partial index on users(avatar) added in migration 027.
CountUsersWithAvatar(ctx context.Context, avatar *string) (int64, error)
CountUsersWithoutTOTP(ctx context.Context) (int64, error)
CreateAPIToken(ctx context.Context, arg CreateAPITokenParams) (sql.Result, error)
CreateAttachment(ctx context.Context, arg CreateAttachmentParams) error
CreateChannel(ctx context.Context, arg CreateChannelParams) (sql.Result, error)
CreateEmoji(ctx context.Context, arg CreateEmojiParams) (CreateEmojiRow, error)
CreateInvite(ctx context.Context, arg CreateInviteParams) error
CreateMessage(ctx context.Context, arg CreateMessageParams) (Message, error)
CreateRole(ctx context.Context, arg CreateRoleParams) (Role, error)
CreateUser(ctx context.Context, arg CreateUserParams) (sql.Result, error)
DeleteChannel(ctx context.Context, id int64) error
DeleteChannelPermission(ctx context.Context, arg DeleteChannelPermissionParams) error
DeleteChannelUserPermission(ctx context.Context, arg DeleteChannelUserPermissionParams) error
DeleteEmoji(ctx context.Context, id int64) (sql.Result, error)
// Sargable text comparison against idx_sessions_expires_at (migration 031).
// expires_at is stored as RFC3339 UTC ("2006-01-02T15:04:05Z") and the
// migration normalized legacy rows, so the caller must pass the cutoff in
// exactly that layout -- a space-separated cutoff would compare wrong.
DeleteExpiredSessions(ctx context.Context, expiresAt string) error
DeleteLockout(ctx context.Context, key string) error
// Avatars are attachments that are never linked to a message on purpose: the
// users.avatar URL is what keeps them alive and authorizes serving them
// (migration 027). Excluding them here is what stops the sweep from destroying
// every avatar in the instance. idx_users_avatar makes the lookup cheap.
DeleteOrphanedAttachments(ctx context.Context, uploadedAt string) ([]string, error)
DeleteOtherSessions(ctx context.Context, arg DeleteOtherSessionsParams) (sql.Result, error)
DeleteRole(ctx context.Context, id int64) error
DeleteSessionByID(ctx context.Context, arg DeleteSessionByIDParams) (sql.Result, error)
DeleteSessionByToken(ctx context.Context, token string) error
DisablePlugin(ctx context.Context, id int64) error
EditMessageContent(ctx context.Context, arg EditMessageContentParams) (Message, error)
// Camera and screenshare share one voice_max_video budget, counted in
// STREAMS, not rows: a channel capped at N simultaneous video streams must
// not let a camera publish ignore screenshare occupants (or vice versa,
// OC-0023), and a single user with both flags set must consume two of the N
// slots, not one (OC-0006) -- so both gates sum `vs2.camera + vs2.screenshare`
// across the channel's rows rather than counting rows where either is set.
// The enabling user's own bit for the flag being set CAN already be 1 at
// gate time (a client that lost track of the server-side flag retries the
// enable), so each gate excludes exactly that one bit from the count --
// see the per-query comments below (OC-0081).
// The channel-wide stream count excludes the requester's own camera flag
// (subtracted via the correlated outer-row reference), so re-enabling an
// already-set camera is idempotent at the cap instead of being refused
// against the requester's own stream (OC-0081). Their screenshare, and
// every other user's streams, still count.
EnableCameraIfUnderLimit(ctx context.Context, arg EnableCameraIfUnderLimitParams) (sql.Result, error)
EnablePlugin(ctx context.Context, id int64) error
// Mirror of EnableCameraIfUnderLimit: the count excludes the requester's
// own screenshare flag so re-enable is idempotent at the cap (OC-0081).
EnableScreenshareIfUnderLimit(ctx context.Context, arg EnableScreenshareIfUnderLimitParams) (sql.Result, error)
EvictOldestSessions(ctx context.Context, arg EvictOldestSessionsParams) error
ForceLogoutUser(ctx context.Context, userID int64) error
// Auth-hot lookup: returns the token only if it is neither revoked nor expired,
// so a resolved row is always usable. Matches the sessions never-expiring
// convention (expires_at IS NULL).
GetActiveAPIToken(ctx context.Context, tokenHash string) (ApiToken, error)
GetAllSettings(ctx context.Context) ([]Setting, error)
GetAllVoiceStates(ctx context.Context) ([]GetAllVoiceStatesRow, error)
GetAttachmentByID(ctx context.Context, id string) (GetAttachmentByIDRow, error)
GetAttachmentWithChannel(ctx context.Context, id string) (GetAttachmentWithChannelRow, error)
GetAuditLog(ctx context.Context, arg GetAuditLogParams) ([]GetAuditLogRow, error)
GetChannel(ctx context.Context, id int64) (GetChannelRow, error)
GetChannelOverrides(ctx context.Context, channelID int64) ([]GetChannelOverridesRow, error)
GetChannelPermission(ctx context.Context, arg GetChannelPermissionParams) (GetChannelPermissionRow, error)
GetChannelUnreadCounts(ctx context.Context, arg GetChannelUnreadCountsParams) ([]GetChannelUnreadCountsRow, error)
GetChannelUserOverrides(ctx context.Context, channelID int64) ([]GetChannelUserOverridesRow, error)
GetChannelUserPermission(ctx context.Context, arg GetChannelUserPermissionParams) (GetChannelUserPermissionRow, error)
GetChannelVoiceStates(ctx context.Context, channelID int64) ([]GetChannelVoiceStatesRow, error)
GetDMParticipantIDs(ctx context.Context, channelID int64) ([]int64, error)
GetDMParticipants(ctx context.Context, channelID int64) ([]GetDMParticipantsRow, error)
// Every participant of every DM the user has open, in one pass. Includes the
// user themselves so a caller can tell "group of three" from "group of three
// others"; the Go layer filters when it needs the others.
GetDMParticipantsForUser(ctx context.Context, userID int64) ([]GetDMParticipantsForUserRow, error)
// The fallback role every member lands on when their role is deleted. Highest
// position wins if a database somehow carries more than one default.
GetDefaultRole(ctx context.Context) (Role, error)
GetEmojiByID(ctx context.Context, id int64) (GetEmojiByIDRow, error)
GetEmojiByShortcode(ctx context.Context, shortcode string) (GetEmojiByShortcodeRow, error)
GetEventsSince(ctx context.Context, arg GetEventsSinceParams) ([]GetEventsSinceRow, error)
GetInvite(ctx context.Context, code string) (GetInviteRow, error)
GetLatestMessageID(ctx context.Context, channelID int64) (interface{}, error)
GetMaxEventSeq(ctx context.Context) (int64, error)
GetMessage(ctx context.Context, id int64) (Message, error)
GetMessagesForAPI(ctx context.Context, arg GetMessagesForAPIParams) ([]GetMessagesForAPIRow, error)
// The highest-privilege account (role with the greatest position), used as the
// default identity for `token create`. FROM is users-only (role position is a
// correlated subquery, not a join) so the row maps through userFromGen exactly
// like GetUserByID, so keep this SELECT list identical to GetUserByID's.
// A :one query already reads a single row via QueryRow, so no LIMIT is needed
// (and an explicit LIMIT 1 is mis-emitted by sqlc here). ORDER BY puts the
// highest-position role first, so that first row is the owner.
// Banned users are excluded: account deletion anonymises the row and sets
// banned = 1 permanently, so without this filter a self-deleted Owner keeps
// outranking every live admin and becomes the default identity for token
// creation forever -- minting tokens the auth layer then 403s on every use.
// The ban_expires arm mirrors auth.IsEffectivelyBanned (and db.notBannedClause)
// so a lapsed temporary ban stays eligible; the replace() normalises the space
// separator form of ban_expires to 'T' before comparing, because ' ' sorts
// below 'T' and a same-day space-form expiry would otherwise read as lapsed.
GetOwnerUser(ctx context.Context) (User, error)
GetReactionCounts(ctx context.Context, messageID int64) ([]GetReactionCountsRow, error)
// Reactors for one (message, emoji) pair, oldest reaction first. The reactions
// table has no timestamp column, so the autoincrement id carries the order.
GetReactionUsers(ctx context.Context, arg GetReactionUsersParams) ([]GetReactionUsersRow, error)
// Reader-pool lookup that lets the channel-focus path skip the UpdateReadState
// UPSERT when the row is already correct, keeping no-op focus events off the
// single writer connection.
GetReadState(ctx context.Context, arg GetReadStateParams) (GetReadStateRow, error)
GetRoleByID(ctx context.Context, id int64) (Role, error)
// Case-insensitive by design: migration 023 enforces uniqueness under the same
// collation, so this is the lookup that agrees with the constraint.
GetRoleByName(ctx context.Context, name string) (Role, error)
GetRoleChannelPermissions(ctx context.Context, roleID int64) ([]GetRoleChannelPermissionsRow, error)
GetRoleForUser(ctx context.Context, id int64) (Role, error)
GetSessionByTokenHash(ctx context.Context, token string) (Session, error)
GetSessionWithBanStatus(ctx context.Context, token string) (GetSessionWithBanStatusRow, error)
GetSetting(ctx context.Context, key string) (string, error)
GetUserByID(ctx context.Context, id int64) (User, error)
GetUserByUsername(ctx context.Context, username string) (User, error)
GetUserChannelPermissions(ctx context.Context, userID int64) ([]GetUserChannelPermissionsRow, error)
GetUserDMChannelIDs(ctx context.Context, userID int64) ([]int64, error)
// A DM row carries no recipient any more: dm_participants holds N users, so
// "the other one" is only well defined for a two-person DM. The participant
// set comes from GetDMParticipantsForUser below, one extra query for the whole
// list rather than one per channel, and the Go layer stitches them together.
GetUserDMChannels(ctx context.Context, userID int64) ([]GetUserDMChannelsRow, error)
GetUserSessions(ctx context.Context, userID int64) ([]Session, error)
GetUserVoiceState(ctx context.Context, userID int64) (GetUserVoiceStateRow, error)
GetUserWithRole(ctx context.Context, id int64) (GetUserWithRoleRow, error)
InsertSession(ctx context.Context, arg InsertSessionParams) (sql.Result, error)
InstallPlugin(ctx context.Context, arg InstallPluginParams) (sql.Result, error)
IsBlocked(ctx context.Context, arg IsBlockedParams) (int64, error)
IsDMParticipant(ctx context.Context, arg IsDMParticipantParams) (int64, error)
IsEitherBlocked(ctx context.Context, arg IsEitherBlockedParams) (int64, error)
IsGroupDM(ctx context.Context, id int64) (int64, error)
// server_muted / server_deafened are deliberately absent from both upserts'
// reset lists: a moderator-imposed mute must survive a channel switch, which
// reaches the ON CONFLICT branch. It is scoped to the voice session:
// leaving voice deletes the row, so a rejoin starts clean.
JoinVoiceChannel(ctx context.Context, arg JoinVoiceChannelParams) error
JoinVoiceChannelIfCapacity(ctx context.Context, arg JoinVoiceChannelIfCapacityParams) (sql.Result, error)
LeaveVoiceChannel(ctx context.Context, userID int64) error
LeaveVoiceChannelIfMatch(ctx context.Context, arg LeaveVoiceChannelIfMatchParams) (sql.Result, error)
// Admin/CLI listing. Never selects token_hash (unrecoverable; only the raw
// token shown at creation is usable).
ListAPITokens(ctx context.Context) ([]ListAPITokensRow, error)
ListAllUsers(ctx context.Context, arg ListAllUsersParams) ([]ListAllUsersRow, error)
ListBlockedUsers(ctx context.Context, blockerID int64) ([]int64, error)
ListBlockersOfUser(ctx context.Context, blockedID int64) ([]int64, error)
ListChannels(ctx context.Context) ([]ListChannelsRow, error)
ListEmoji(ctx context.Context) ([]ListEmojiRow, error)
ListInvites(ctx context.Context) ([]ListInvitesRow, error)
// 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.
ListMembers(ctx context.Context) ([]ListMembersRow, error)
ListPlugins(ctx context.Context) ([]Plugin, error)
// Highest rank first. Positions are only "unique enough": reorder normalizes
// them, but creating a role inserts just below the actor and may tie with an
// existing role, so id is a tiebreaker. Without it SQLite may return tied rows
// in any order, and the admin panel derives its reorder payload from this
// order, so a single move-up would silently shuffle the tied roles.
// NOTE: keep comments in this file ASCII-only. sqlc mixes byte and rune
// offsets when stripping them, so a non-ASCII character here truncates the
// generated SQL of THIS and every following query by the byte/rune delta.
ListRoles(ctx context.Context) ([]Role, error)
ListUserIDsByRole(ctx context.Context, roleID int64) ([]int64, error)
ListUserSessions(ctx context.Context, userID int64) ([]Session, error)
LoadActiveLockouts(ctx context.Context, expiresAt string) ([]RateLockout, error)
LogAudit(ctx context.Context, arg LogAuditParams) error
// 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.
MarkUserDisconnected(ctx context.Context, id int64) error
OpenDM(ctx context.Context, arg OpenDMParams) (int64, error)
// seq is supplied by the hub so the row seq matches the wrapped-payload seq.
PersistEvent(ctx context.Context, arg PersistEventParams) error
PluginKVDelete(ctx context.Context, arg PluginKVDeleteParams) error
PluginKVGet(ctx context.Context, arg PluginKVGetParams) ([]byte, error)
PluginKVSet(ctx context.Context, arg PluginKVSetParams) error
PruneEventsOlderThan(ctx context.Context, createdAt time.Time) (int64, error)
RemoveDMParticipant(ctx context.Context, arg RemoveDMParticipantParams) error
RemoveReaction(ctx context.Context, arg RemoveReactionParams) (sql.Result, error)
// 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.
ResetAllUserStatuses(ctx context.Context) error
RevokeAPIToken(ctx context.Context, id int64) (sql.Result, error)
RevokeAPITokenByLabel(ctx context.Context, label string) (sql.Result, error)
RevokeInvite(ctx context.Context, code string) error
SetChannelSlowMode(ctx context.Context, arg SetChannelSlowModeParams) error
SetChannelVoiceMaxUsers(ctx context.Context, arg SetChannelVoiceMaxUsersParams) error
SetDMChannelName(ctx context.Context, arg SetDMChannelNameParams) error
SetMessagePinned(ctx context.Context, arg SetMessagePinnedParams) (sql.Result, error)
SetRolePosition(ctx context.Context, arg SetRolePositionParams) error
SetSetting(ctx context.Context, arg SetSettingParams) error
SoftDeleteMessage(ctx context.Context, id int64) error
TouchAPIToken(ctx context.Context, tokenHash string) error
TouchSession(ctx context.Context, token string) error
UnbanUser(ctx context.Context, id int64) error
UnblockUser(ctx context.Context, arg UnblockUserParams) error
UninstallPlugin(ctx context.Context, id int64) error
UpdateChannel(ctx context.Context, arg UpdateChannelParams) error
// Marking a channel read also clears its mention badge: channel_focus is the
// only caller, and a focused channel has no outstanding mentions by definition.
UpdateReadState(ctx context.Context, arg UpdateReadStateParams) error
UpdateRole(ctx context.Context, arg UpdateRoleParams) error
// Separate from UpdateUserProfile because a custom status arrives over the
// WebSocket presence path, not the REST profile PATCH, and must not be able to
// clobber the username/avatar of a profile edit racing it.
UpdateUserCustomStatus(ctx context.Context, arg UpdateUserCustomStatusParams) error
UpdateUserIdentityKey(ctx context.Context, arg UpdateUserIdentityKeyParams) error
UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error
UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (sql.Result, error)
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) error
UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) error
UpdateUserTOTPSecret(ctx context.Context, arg UpdateUserTOTPSecretParams) error
UpdateVoiceCamera(ctx context.Context, arg UpdateVoiceCameraParams) error
UpdateVoiceDeafen(ctx context.Context, arg UpdateVoiceDeafenParams) error
UpdateVoiceMute(ctx context.Context, arg UpdateVoiceMuteParams) error
UpdateVoiceScreenshare(ctx context.Context, arg UpdateVoiceScreenshareParams) error
UpsertChannelPermission(ctx context.Context, arg UpsertChannelPermissionParams) error
UpsertChannelUserPermission(ctx context.Context, arg UpsertChannelUserPermissionParams) error
UpsertLockout(ctx context.Context, arg UpsertLockoutParams) error
UseInviteAtomic(ctx context.Context, code string) (sql.Result, error)
UserCount(ctx context.Context) (int64, error)
}
var _ Querier = (*Queries)(nil)