social

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package social owns S26's stars / watches / events surface. The package is read-mostly from the rest of the runtime: notifications fan-out (S29) reads `watches` for routing, the activity feed (post-MVP) reads `domain_events` for public timelines, and the repo profile reads cached counts. Mutations come through the orchestrator entrypoints below.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotLoggedIn       = errors.New("social: login required")
	ErrInvalidWatchLevel = errors.New("social: watch level must be all, participating, or ignore")
	ErrStarRateLimit     = errors.New("social: star/unstar rate limit exceeded")
)

Errors surfaced to handlers.

Functions

func AutoWatchOnCollab

func AutoWatchOnCollab(ctx context.Context, deps Deps, userID, repoID int64) error

AutoWatchOnCollab inserts a `level='all'` row when no preference exists. Triggered by S15's collaborator-add path. Non-destructive: if the user has already chosen a level (including `ignore`), their choice is preserved.

Matches GitHub: collaborators get full notifications by default; they can opt down to `participating` or `ignore` later.

func AutoWatchOnInvolvement

func AutoWatchOnInvolvement(ctx context.Context, deps Deps, userID, repoID int64) error

AutoWatchOnInvolvement inserts a `level='participating'` row when no preference exists. Triggered by issues.AddComment, mention resolution, assignment, review-requested. Non-destructive.

Matches GitHub: any first-touch involvement (commenting, getting mentioned, getting assigned) auto-subscribes the user to that thread's notifications, but only at the participating level so a drive-by mention doesn't flood them with future events.

func Emit

func Emit(ctx context.Context, deps Deps, p EmitParams) error

Emit writes one row to domain_events. Non-fatal at the caller's discretion; orchestrators typically log on error rather than failing the whole transaction (the in-band action is more important than the event log).

func HasStar

func HasStar(ctx context.Context, deps Deps, userID, repoID int64) (bool, error)

HasStar reports whether the user has starred the repo. Used by the star button on the repo page to render the toggled state.

func SetWatch

func SetWatch(ctx context.Context, deps Deps, actorUserID, repoID int64, level WatchLevel) error

SetWatch upserts an explicit watch level. The handler authorizes via policy.Can(ActionWatchSet, repo) before calling.

func Star

func Star(ctx context.Context, deps Deps, actorUserID, repoID int64, repoIsPublic bool) error

Star idempotently records a star. Re-starring an already-starred repo is a no-op (the underlying INSERT … ON CONFLICT DO NOTHING + AFTER INSERT trigger combination keeps star_count consistent).

The handler MUST authorize via policy.Can(ActionStarCreate, repo) before calling — this orchestrator trusts that the actor has read access to the repo and is logged in.

Emits a `star` event into domain_events with `public = repoIsPublic`.

func UnsetWatch

func UnsetWatch(ctx context.Context, deps Deps, actorUserID, repoID int64) error

UnsetWatch removes the explicit row, returning the user to the implicit `participating` default.

func Unstar

func Unstar(ctx context.Context, deps Deps, actorUserID, repoID int64, repoIsPublic bool) error

Unstar removes the star idempotently. Unstarring a non-starred repo is a no-op. Emits an `unstar` event for symmetry.

Types

type Deps

type Deps struct {
	Pool    *pgxpool.Pool
	Limiter *throttle.Limiter
	Logger  *slog.Logger
	Audit   *audit.Recorder
}

Deps wires the package against the rest of the runtime. Pool is required. Limiter governs the per-user star/unstar rate cap (spec pitfall: trending-manipulation abuse vector). Logger is optional (falls back to discarding when nil). Audit is optional; when set, state-changing operations record an audit row.

type EmitParams

type EmitParams struct {
	ActorUserID int64
	Kind        string
	RepoID      int64 // 0 for user-scoped
	SourceKind  string
	SourceID    int64
	Public      bool
	Payload     []byte // already-marshaled JSON; pass `[]byte("{}")` for empty
}

EmitEvent is the canonical seam for inserting a row into `domain_events`. Other packages (issues, pulls, repos lifecycle) will call this rather than reaching into the sqlc query directly, so the event-shape contract has one place to evolve as S29 and S33 wire up their consumers.

Pass repoID = 0 for user-scoped events (where there's no repo involved). The handler / orchestrator owns the public-flag decision: public-repo events should set true; private-repo events must set false.

type WatchLevel

type WatchLevel string

WatchLevel mirrors the DB enum so handlers can pass typed values without importing socialdb.

const (
	WatchAll           WatchLevel = "all"
	WatchParticipating WatchLevel = "participating"
	WatchIgnore        WatchLevel = "ignore"
)

func CurrentLevel

func CurrentLevel(ctx context.Context, deps Deps, userID, repoID int64) (WatchLevel, error)

CurrentLevel returns the actor's current watch level for the repo, resolving the implicit `participating` default when no row exists.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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