Documentation
¶
Overview ¶
Package calendar wraps Google Calendar event creation behind a small interface so the rest of JobForge stays vendor-agnostic. Eventually this could grow Outlook/CalDAV implementations behind the same Client.
Token storage and OAuth lifecycle live in oauth.go. The Google API surface is intentionally tiny: create event, delete event. We are not trying to be a calendar app.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoToken = errors.New("no Google OAuth token; run `jobforge calendar auth` first")
ErrNoToken signals that no stored OAuth token was found at Paths.GoogleTokenFile. Callers should prompt the user to run `jobforge calendar auth` and not treat it as a fatal error.
var ErrNotConfigured = errors.New("google.client_id and google.client_secret are not set in config.json")
ErrNotConfigured signals that config.json has no google.client_id or google.client_secret. Different from ErrNoToken — auth can't even start until the user pastes their credentials in.
Functions ¶
func DeleteToken ¶
DeleteToken removes the token file. Used by `calendar revoke`. Returns nil if the file is already gone.
func HTTPClient ¶
func HTTPClient(ctx context.Context, s config.GoogleSettings, tokenFile string) (*http.Client, error)
HTTPClient returns an *http.Client whose transport auto-refreshes tokens and persists any new ones to tokenFile. Pass it to the Google Calendar service constructor.
func LoadToken ¶
LoadToken reads a previously-saved token. Returns ErrNoToken if the file doesn't exist so callers can prompt the user to authorize.
Types ¶
type AuthResult ¶
type AuthResult struct {
Token *oauth2.Token
Email string // best-effort: the Google account email, blank if not derivable
SavedAt string // tokenFile path (for the success message)
}
AuthResult is what Authorize hands back to the CLI. The token is also persisted to tokenFile inside Authorize, so callers don't need to save it themselves.
func Authorize ¶
func Authorize(ctx context.Context, s config.GoogleSettings, tokenFile string, openBrowser func(url string) error) (AuthResult, error)
Authorize runs the full OAuth 2.0 loopback flow:
- Start a local HTTP server on a random port to receive Google's redirect.
- Open the user's browser to Google's consent screen.
- Wait for the redirect with the auth code.
- Exchange the code for an access + refresh token.
- Persist the token to tokenFile.
The caller (CLI) handles printing instructions, opening the browser, and surfacing errors. We block until either the redirect lands or ctx cancels.
type Client ¶
type Client interface {
// CreateEvent creates one event and returns the provider's event ID.
// The ID is needed later for deletion or updates.
CreateEvent(ctx context.Context, e Event) (string, error)
// DeleteEvent removes an event by provider ID. Idempotent: deleting
// an already-gone event returns nil.
DeleteEvent(ctx context.Context, eventID string) error
}
Client is the abstraction over a calendar provider. Implementations are responsible for their own auth + retries.
func NewGoogleClient ¶
func NewGoogleClient(ctx context.Context, s config.GoogleSettings, tokenFile string) (Client, error)
NewGoogleClient builds a Client wired to the user's stored token. Returns ErrNoToken if the user hasn't run `calendar auth` yet, and ErrNotConfigured if config.json lacks ClientID/ClientSecret.
type Event ¶
type Event struct {
Summary string // "Interview: Backend Engineer at Acme"
Description string // multi-line: job URL, notes, prep links
Location string // "Zoom", "Acme HQ - 555 Market St", etc.
Start time.Time // event start
End time.Time // event end (required unless AllDay)
AllDay bool // ignore Start/End times, use Start's Date
Attendees []string // email addresses
}
Event is the calendar-agnostic event we hand off to the provider. Times are timezone-aware (use time.Local or an explicit Location). AllDay events ignore Start/End times — Date alone is used.
func EventForJobDeadline ¶
EventForJobDeadline constructs an all-day event reminding the user about an application deadline. We use all-day because deadlines are date-granular ("apply by Friday") and we don't want them blocking a specific hour on the user's calendar.
func EventForJobInterview ¶
func EventForJobInterview(jobTitle, company, jobURL string, when time.Time, duration time.Duration, location string, attendees []string) Event
EventForJobInterview constructs an Event for an interview tied to a job. Pure function, no I/O — extracted so the CLI can show the user the exact event payload before we call CreateEvent.