web

package
v0.0.0-...-257955c Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: AGPL-3.0 Imports: 25 Imported by: 0

Documentation

Overview

Package web holds the Discourse integration's HTTP handlers: the webhook endpoint (this file) and the operator surface. The webhook endpoint is the latency layer between sweeps (design.md D3): user_created events link brand-new forum accounts within seconds of first login, and user_added_to_group/user_removed_from_group events on managed groups trigger targeted reconciles that correct forum-side drift. Missing or failed events cost only latency — the sweep restores correctness.

Index

Constants

View Source
const WebhookPath = "/webhooks/discourse"

WebhookPath is the Discourse webhook endpoint, declared CSRF-exempt by the adapter when (and only when) the webhook secret is configured.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConflictViewModel

type ConflictViewModel struct {
	DiscourseUsername string
	PersonID          string
}

ConflictViewModel is one conflicted link.

type DiscourseOperatorHandler

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

DiscourseOperatorHandler serves the Discourse integration's operator surface: entitlement→group mapping management and link/sync visibility (spec: discourse-operator-surface).

func NewDiscourseOperatorHandler

func NewDiscourseOperatorHandler(cfg DiscourseOperatorHandlerConfig) (*DiscourseOperatorHandler, error)

NewDiscourseOperatorHandler composes the operator shell with the integration's body partial.

func (*DiscourseOperatorHandler) CreateMapping

func (h *DiscourseOperatorHandler) CreateMapping(w http.ResponseWriter, r *http.Request)

CreateMapping handles POST /partials/operator/discourse/mappings: validate against the forum (group exists, not automatic), then insert (spec: "Entitlement-to-group mapping management").

func (*DiscourseOperatorHandler) DeleteMapping

func (h *DiscourseOperatorHandler) DeleteMapping(w http.ResponseWriter, r *http.Request)

DeleteMapping handles DELETE /partials/operator/discourse/mappings/{mappingID}. Unmapping stops management; forum-side membership is left as-is (spec: "Unmapping a group").

func (*DiscourseOperatorHandler) GetPage

GetPage handles GET <OperatorSurfacePath>.

type DiscourseOperatorHandlerConfig

type DiscourseOperatorHandlerConfig struct {
	DB         *sql.DB
	Logger     *slog.Logger
	AuthConfig *auth.Config
	// Client is nil when the integration is unconfigured (the page then
	// renders only the unconfigured notice; mutation routes are unmounted).
	Client     *dcclient.Client
	Temporal   temporalsdk.Client
	Configured bool
	// TemplatesFS is the integration's own template tree, injected by the
	// adapter (same cycle argument as FedWiki's operator handler).
	TemplatesFS fs.FS
	// SweepScheduleID names the sweep SCHEDULE to report health from
	// (this integration's workflows.SyncScheduleID; injected so this
	// package needs no import of its own workflows package). Runs are
	// resolved through the schedule because schedule-spawned executions
	// get timestamp-suffixed workflow IDs — see
	// workflows.ScheduleRunStatus.
	SweepScheduleID string
}

DiscourseOperatorHandlerConfig configures the handler.

type MappingViewModel

type MappingViewModel struct {
	MappingID   string
	ResourceKey string
	// DisplayName is the resource key's friendly name, from the same
	// resource-key catalog the mapping-form picker uses, so the mappings
	// table leads with it instead of the raw key (ui-vocabulary 4.3).
	DisplayName string
	GroupName   string
	GroupID     int64
	CreatedAt   string
	DeleteURL   string
}

MappingViewModel is one entitlement→group mapping row.

type MemberForumData

type MemberForumData struct {
	// AccessGranted: a granted forum-access boolean entitlement on any of
	// the member's organizations' pools (union semantics, the same
	// desired-set predicate the sync sweep uses).
	AccessGranted bool
	// Linked: a healthy user_links row exists for this person. A
	// 'conflict'-status link blocks delivery, so it renders as not-linked
	// (the guidance state), never as an error.
	Linked   bool
	ForumURL string
	Mode     string // linkage mode; selects the not-yet-linked guidance copy
	Error    string
}

MemberForumData holds data for the discourse_member_forum.html partial — the member dashboard card body (dashboard-display-genericity). Read-only by design: the partial reports fulfillment state and links to the forum; linkage is automatic per mode, so there is nothing for the member to mutate here.

type MemberForumHandler

type MemberForumHandler struct {
	Q          dcmod.Querier
	Logger     *slog.Logger
	AuthConfig *auth.Config
	ForumURL   string
	Mode       linkage.Mode
	Keys       []string
	Templates  *server.SafeTemplates
}

MemberForumHandler serves the member dashboard card body: the signed-in member's forum access and link state.

func NewMemberForumHandler

func NewMemberForumHandler(cfg MemberForumHandlerConfig) (*MemberForumHandler, error)

NewMemberForumHandler creates a new MemberForumHandler.

func (*MemberForumHandler) GetForumAccess

func (h *MemberForumHandler) GetForumAccess(w http.ResponseWriter, r *http.Request)

GetForumAccess handles GET /partials/discourse/forum-access.

func (*MemberForumHandler) RenderForPerson

func (h *MemberForumHandler) RenderForPerson(w http.ResponseWriter, ctx context.Context, personID string)

RenderForPerson renders the card body for one person. Exported as the session-independent seam: GetForumAccess resolves the person from the authenticated session; DB-backed tests call this directly (constructing a live session in an external test package would drag in the whole auth stack for no additional coverage).

type MemberForumHandlerConfig

type MemberForumHandlerConfig struct {
	DB         *sql.DB
	Logger     *slog.Logger
	AuthConfig *auth.Config
	// ForumURL is the configured Discourse base URL — the "Visit forum"
	// link target.
	ForumURL string
	Mode     linkage.Mode
	// ResourceKeys are the forum-access boolean keys to check (from the
	// provider manifest's declared ResourceKeys — no literal key names in
	// this package); access is granted when any is desired for the person.
	ResourceKeys []string
	// TemplatesFS is Discourse's own template directory, supplied by the
	// Adapter from its embedded tree (see the operator handler's identical
	// arrangement for the cycle rationale).
	TemplatesFS fs.FS
}

MemberForumHandlerConfig holds configuration for MemberForumHandler.

type OperatorPageData

type OperatorPageData struct {
	Configured bool

	// Sync health (latest sweep execution, from Temporal).
	SweepStatus string
	SweepTime   string

	Mappings     []MappingViewModel
	ResourceKeys []ResourceKeyOption
	Unlinked     []UnlinkedPersonViewModel
	Conflicts    []ConflictViewModel

	// Add-mapping form state (422 re-render path).
	FieldErrors web.FieldErrors
	FormValues  map[string]string

	Error string
}

OperatorPageData is the discourse_operator.html body payload.

type ResourceKeyOption

type ResourceKeyOption struct {
	Key         string
	DisplayName string
}

ResourceKeyOption is a select option for the mapping form.

type StarterFunc

type StarterFunc func(personID string) error

StarterFunc starts a person's targeted reconcile. Production wraps the Temporal client (per-person workflow ID serialization); tests inject a recorder.

type UnlinkedPersonViewModel

type UnlinkedPersonViewModel struct {
	DisplayName string
	Email       string
}

UnlinkedPersonViewModel is one entitled-but-unlinked person.

type WebhookHandler

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

WebhookHandler verifies, dedupes, and dispatches Discourse webhook events.

func NewWebhookHandler

func NewWebhookHandler(cfg WebhookHandlerConfig) *WebhookHandler

NewWebhookHandler constructs the handler.

func (*WebhookHandler) RegisterRoutes

func (h *WebhookHandler) RegisterRoutes(mux *http.ServeMux)

RegisterRoutes mounts the webhook endpoint.

type WebhookHandlerConfig

type WebhookHandlerConfig struct {
	DB     *sql.DB
	Logger *slog.Logger
	// Secret is the shared webhook secret (discourse-webhook-secret).
	Secret string
	// Mode selects reverse resolution for user_created events.
	Mode linkage.Mode
	// Client resolves admin user records (oidc/discourseconnect reverse
	// resolution).
	Client *client.Client
	// StartReconcile launches the targeted per-person reconcile.
	StartReconcile StarterFunc
}

WebhookHandlerConfig configures the webhook endpoint.

Jump to

Keyboard shortcuts

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