discord

package
v0.0.0-...-ddef314 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: MIT Imports: 20 Imported by: 0

README

discord

Discord integration for Conway: OAuth2 login/account linking, asynchronous guild role reconciliation, and configurable webhook notifications driven by SQL triggers.

Functionality

  • Account linking (GET /discord/login, /discord/callback): authenticated users link their Discord account; stores discord_user_id, discord_email, discord_avatar on the member row.
  • Discord login (GET /login/discord, /login/discord/callback): unauthenticated sign-in. Resolves the member by discord_user_id first, then by email. If no account exists, delegates to SignupConfirmFunc (set via SetSignupConfirm); falls back to direct member creation if unset. Login completion is delegated to LoginCompleteFunc (set via SetLoginCompleter). Both must be wired before routes are attached for the respective flows to work. Discord accounts without a verified email are rejected.
  • Role sync: a paid payment_status maps to membership of the configured RoleID in the configured guild. Reconciliation is driven by the workqueue pattern in engine and rate-limited to maxRPS = 3 API requests/second.
  • Webhooks: discord_webhooks rows define URL, message template ({placeholder} syntax), username, and a SQL trigger (trigger_table + trigger_op + optional when_clause). Trigger creation/dispatch lives outside this file set; this module owns the schema and migrations.

Behavioral details

  • Configuration is loaded dynamically per request via config.Loader[Config] (SetConfigLoader must be called at startup). Workers always run and no-op when bot/OAuth config is incomplete.
  • scheduleFullReconciliation runs every minute, marking up to 10 members whose discord_last_synced is older than SyncIntervalHours (default 24, clamped 1-168) as needing sync by setting discord_last_synced = NULL.
  • GetItem atomically claims a member needing sync via UPDATE ... RETURNING, setting discord_last_synced = unixepoch() to prevent double-claiming.
  • On sync success, discord_username and discord_avatar are updated. On failure, discord_last_synced is pushed forward with exponential backoff (starting at 300s, capped at 86400s).
  • Display name resolution priority: guild nick > global_name > username. Avatar priority: guild-specific avatar > user avatar. Avatars are fetched as raw PNG bytes and stored on the member row.
  • OAuth state is a JWT signed by engine.TokenIssuer. Account-linking state expires in 1 minute and binds to the user ID; login state expires in 5 minutes and carries the post-login callback_uri in the Issuer claim.
  • Login flow stores Discord email lowercased and clears discord_last_synced to trigger an async avatar/role refresh.
  • Schema migrations in module.go use ALTER TABLE ADD COLUMN and ignore errors (idempotent on existing DBs). triggers.go migrates legacy trigger_event-based webhooks to the new SQL-trigger model and folds the removed discord_webhook_conditions table into discord_webhooks.when_clause before dropping it. Old metrics samplings and the legacy members_signup_notification / discord_webhook_on_member_event triggers are dropped on startup.
  • All Discord API errors and OAuth callbacks are recorded via engine.EventLogger.

Documentation

Overview

templ: version: v0.3.1001

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// OAuth2 Configuration
	ClientID     string `json:"client_id" config:"label=Client ID,section=oauth,help=The Application ID from Discord Developer Portal."`
	ClientSecret string `json:"client_secret" config:"label=Client Secret,secret,section=oauth,help=Keep this confidential."`

	// Bot Configuration
	BotToken string `json:"bot_token" config:"label=Bot Token,secret,section=bot"`
	GuildID  string `` /* 166-byte string literal not displayed */
	RoleID   string `` /* 176-byte string literal not displayed */

	// Sync Settings
	SyncIntervalHours int `` /* 199-byte string literal not displayed */
}

Config holds Discord-related configuration.

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the Discord configuration.

type DiscordUserInfo

type DiscordUserInfo struct {
	ID     string
	Email  string
	Avatar []byte
}

type GuildMemberInfo

type GuildMemberInfo struct {
	HasRole     bool
	DisplayName string // nick > global_name > username
	Avatar      []byte
}

type LoginCompleteFunc

type LoginCompleteFunc func(w http.ResponseWriter, r *http.Request, memberID int64, callbackURI string)

LoginCompleteFunc is called by the discord module to finish a login flow. It receives the member ID and the callback URI to redirect to after login.

type Module

type Module struct {
	// contains filtered or unexported fields
}

func New

func New(db *sql.DB, self *url.URL, iss *engine.TokenIssuer, eventLogger *engine.EventLogger) *Module

func (*Module) AttachRoutes

func (m *Module) AttachRoutes(router *engine.Router)

func (*Module) AttachWorkers

func (m *Module) AttachWorkers(mgr *engine.ProcMgr)

func (*Module) ConfigSpec

func (m *Module) ConfigSpec() config.Spec

ConfigSpec returns the Discord configuration specification.

func (*Module) GetItem

func (m *Module) GetItem(ctx context.Context) (item *syncItem, err error)

func (*Module) IsLoginEnabled

func (m *Module) IsLoginEnabled(ctx context.Context) bool

IsLoginEnabled reports whether Discord OAuth login is available.

func (*Module) ProcessItem

func (m *Module) ProcessItem(ctx context.Context, item *syncItem) error

func (*Module) SetConfigLoader

func (m *Module) SetConfigLoader(store *config.Store)

SetConfigLoader sets the typed config loader for this module.

func (*Module) SetLoginCompleter

func (m *Module) SetLoginCompleter(f LoginCompleteFunc)

SetLoginCompleter configures the function used to complete Discord-based logins. This must be called before routes are attached.

func (*Module) SetSignupConfirm

func (m *Module) SetSignupConfirm(f SignupConfirmFunc)

SetSignupConfirm configures the function used to show the signup confirmation page. This must be called before routes are attached.

func (*Module) UpdateItem

func (m *Module) UpdateItem(ctx context.Context, item *syncItem, success bool) error

type SignupConfirmFunc

type SignupConfirmFunc func(w http.ResponseWriter, r *http.Request, email, provider, callbackURI string)

SignupConfirmFunc is called when no account exists for the user's email. It renders a confirmation page asking the user to confirm account creation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL