timeclient

package
v0.1.4 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	APIPrefix      = "/api/v4"
	DefaultTimeout = 30 * time.Second

	MeEndpoint             = APIPrefix + "/users/me"
	MyTeamsEndpoint        = APIPrefix + "/users/me/teams"
	TeamByNameEndpoint     = APIPrefix + "/teams/name/%s"
	UserChannelsEndpoint   = APIPrefix + "/users/%s/teams/%s/channels"
	UserByUsernameEndpoint = APIPrefix + "/users/username/%s"
	ChannelPostsEndpoint   = APIPrefix + "/channels/%s/posts"
)
View Source
const (
	DefaultBaseURL     = "https://time.cu.ru"
	DefaultTeamName    = "tsentralnyy-universitet"
	DefaultBotUsername = "cu_notification_bot"
	CookieName         = "MMAUTHTOKEN"

	EnvBaseURL     = "CU_MM_BASE_URL"
	EnvTeamName    = "CU_MM_TEAM"
	EnvBotUsername = "CU_MM_BOT_USERNAME"
	EnvToken       = "CU_MM_TOKEN" // #nosec G101 -- env var name, not a credential
)

Defaults for the Mattermost instance run by Central University. Override via environment variables if the deployment changes.

Variables

This section is empty.

Functions

func CookieFilePath

func CookieFilePath() (string, error)

func LoadCookie

func LoadCookie() (string, error)

func LoginWithBrowser

func LoginWithBrowser(ctx context.Context, timeout time.Duration) (string, error)

LoginWithBrowser opens Chrome for Mattermost SSO login and captures MMAUTHTOKEN.

func SaveCookie

func SaveCookie(cookie string) error

func StorageDir

func StorageDir(channelID string) (string, error)

StorageDir returns the per-channel directory under ~/.cu-cli/mm/<channelID>.

Types

type APIError

type APIError struct {
	ID            string `json:"id"`
	Message       string `json:"message"`
	DetailedError string `json:"detailed_error"`
	StatusCode    int    `json:"status_code"`
}

APIError mirrors the Mattermost error envelope.

func (*APIError) Error

func (e *APIError) Error() string

type Channel

type Channel struct {
	ID          string `json:"id"`
	TeamID      string `json:"team_id"`
	Type        string `json:"type"` // "O" public, "P" private, "D" direct, "G" group
	Name        string `json:"name"`
	DisplayName string `json:"display_name"`
}

Channel represents a Mattermost channel. For direct messages the `name` field has the form "<userID1>__<userID2>" sorted lexicographically.

type Client

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

func NewClient

func NewClient(token string) *Client

func NewClientFromEnv

func NewClientFromEnv() (*Client, error)

NewClientFromEnv loads a token from CU_MM_TOKEN or the saved cookie file and uses CU_MM_BASE_URL when set, otherwise DefaultBaseURL.

func NewClientWithBase

func NewClientWithBase(token, baseURL string) *Client

func (*Client) BaseURL

func (c *Client) BaseURL() string

func (*Client) GetChannelPosts

func (c *Client) GetChannelPosts(ctx context.Context, channelID string, q PostsQuery) (*PostList, error)

GetChannelPosts returns a page of posts for a channel.

func (*Client) GetMe

func (c *Client) GetMe(ctx context.Context) (*User, error)

GetMe returns the authenticated user.

func (*Client) GetMyTeams

func (c *Client) GetMyTeams(ctx context.Context) ([]Team, error)

GetMyTeams returns teams the authenticated user belongs to.

func (*Client) GetTeamByName

func (c *Client) GetTeamByName(ctx context.Context, name string) (*Team, error)

GetTeamByName looks up a team by its URL slug.

func (*Client) GetUserByUsername

func (c *Client) GetUserByUsername(ctx context.Context, username string) (*User, error)

GetUserByUsername resolves a user by their username (without leading '@').

func (*Client) GetUserChannelsForTeam

func (c *Client) GetUserChannelsForTeam(ctx context.Context, userID, teamID string) ([]Channel, error)

GetUserChannelsForTeam returns channels the user is a member of for the given team.

func (*Client) ResolveBotChannel

func (c *Client) ResolveBotChannel(
	ctx context.Context,
	teamName, botUsername string,
) (*User, *User, *Channel, error)

ResolveBotChannel finds the direct-message channel between the authenticated user and the bot identified by botUsername within the team teamName. teamName may be empty: the first team the user belongs to is used.

func (*Client) Token

func (c *Client) Token() string

func (*Client) ValidateToken

func (c *Client) ValidateToken(ctx context.Context) error

ValidateToken does a cheap call to /users/me to confirm the token works.

type Config

type Config struct {
	BaseURL     string
	TeamName    string
	BotUsername string
}

Config groups the tunable knobs for the Mattermost gateway.

func LoadConfig

func LoadConfig() Config
func (c Config) Permalink(postID string) string

Permalink builds the in-app URL for a post: <base>/<team>/pl/<postID>.

type NotificationsSource

type NotificationsSource struct {
	Store *Store
}

NotificationsSource adapts the JSONL Store to notifications.PostSource.

func NewNotificationsSource

func NewNotificationsSource(s *Store) *NotificationsSource

func (*NotificationsSource) LoadPosts

type Post

type Post struct {
	ID        string         `json:"id"`
	ChannelID string         `json:"channel_id"`
	UserID    string         `json:"user_id"`
	RootID    string         `json:"root_id"`
	Type      string         `json:"type"`
	Message   string         `json:"message"`
	CreateAt  int64          `json:"create_at"` // unix ms
	UpdateAt  int64          `json:"update_at"`
	DeleteAt  int64          `json:"delete_at"`
	FileIDs   []string       `json:"file_ids,omitempty"`
	Props     map[string]any `json:"props,omitempty"`
	Metadata  map[string]any `json:"metadata,omitempty"`
}

Post is a chat message.

type PostList

type PostList struct {
	Order      []string         `json:"order"`
	Posts      map[string]*Post `json:"posts"`
	NextPostID string           `json:"next_post_id"`
	PrevPostID string           `json:"prev_post_id"`
}

PostList is the standard Mattermost paginated post response.

type PostsQuery

type PostsQuery struct {
	Since   int64  // unix ms; if >0 returns posts created/updated since this time
	After   string // post ID; returns posts after this one
	Before  string // post ID; returns posts before this one
	Page    int
	PerPage int
}

PostsQuery controls /channels/{id}/posts paging.

type State

type State struct {
	ChannelID    string `json:"channel_id"`
	LastPostID   string `json:"last_post_id"`
	LastCreateAt int64  `json:"last_create_at"`
	SyncedAt     int64  `json:"synced_at"`
	BotUserID    string `json:"bot_user_id,omitempty"`
	BotUsername  string `json:"bot_username,omitempty"`
}

State persists incremental sync progress for a channel.

type Store

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

Store is an append-only JSONL store for posts plus a small JSON state file.

func NewStore

func NewStore(channelID string) (*Store, error)

func (*Store) AppendPosts

func (s *Store) AppendPosts(posts []*Post) (int, string, int64, error)

AppendPosts writes posts as JSONL, ordered by CreateAt ascending. Returns the number of new posts persisted and the latest seen create_at/id.

func (*Store) Dir

func (s *Store) Dir() string

func (*Store) LoadState

func (s *Store) LoadState() (State, error)

LoadState reads state.json or returns a zero-value State if missing.

func (*Store) ReadLastN

func (s *Store) ReadLastN(n int) ([]Post, error)

ReadLastN returns the last n posts from storage ordered by CreateAt ascending.

func (*Store) SaveState

func (s *Store) SaveState(st State) error

SaveState writes state.json atomically.

type StoreSource

type StoreSource struct {
	Store *Store
}

StoreSource adapts a local JSONL Store to the recordings.PostSource interface.

func NewStoreSource

func NewStoreSource(s *Store) *StoreSource

func (*StoreSource) LoadPosts

func (s *StoreSource) LoadPosts(_ context.Context) ([]recordings.RawPost, error)

LoadPosts streams every post from the channel JSONL file. limit==0 means "all posts".

type Team

type Team struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	DisplayName string `json:"display_name"`
}

Team is a trimmed Mattermost team.

type User

type User struct {
	ID       string `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

User is a trimmed Mattermost user.

Jump to

Keyboard shortcuts

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