feat: add configuration support to enbas #32
30 changed files with 425 additions and 220 deletions
|
@ -31,5 +31,8 @@ linters-settings:
|
||||||
linters:
|
linters:
|
||||||
enable-all: true
|
enable-all: true
|
||||||
disable:
|
disable:
|
||||||
#- json
|
- exhaustivestruct
|
||||||
|
- exhaustruct
|
||||||
|
- gomnd
|
||||||
|
- tagliatelle
|
||||||
fast: false
|
fast: false
|
||||||
|
|
|
@ -10,15 +10,16 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
binaryVersion string
|
binaryVersion string //nolint:gochecknoglobals
|
||||||
buildTime string
|
buildTime string //nolint:gochecknoglobals
|
||||||
goVersion string
|
goVersion string //nolint:gochecknoglobals
|
||||||
gitCommit string
|
gitCommit string //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -29,22 +30,11 @@ func main() {
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
var (
|
var (
|
||||||
configDir string
|
configDir string
|
||||||
cacheDir string
|
noColor *bool
|
||||||
pager string
|
|
||||||
imageViewer string
|
|
||||||
videoPlayer string
|
|
||||||
maxTerminalWidth int
|
|
||||||
noColor *bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory")
|
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory")
|
||||||
flag.StringVar(&cacheDir, "cache-dir", "", "Specify your cache directory")
|
|
||||||
flag.StringVar(&pager, "pager", "", "Specify your preferred pager to page through long outputs. This is disabled by default.")
|
|
||||||
flag.StringVar(&imageViewer, "image-viewer", "", "Specify your favourite image viewer.")
|
|
||||||
flag.StringVar(&videoPlayer, "video-player", "", "Specify your favourite video player.")
|
|
||||||
flag.IntVar(&maxTerminalWidth, "max-terminal-width", 80, "Specify the maximum terminal width when displaying resources on screen.")
|
|
||||||
|
|
||||||
flag.BoolFunc("no-color", "Disable ANSI colour output when displaying text on screen", func(value string) error {
|
flag.BoolFunc("no-color", "Disable ANSI colour output when displaying text on screen", func(value string) error {
|
||||||
boolVal, err := strconv.ParseBool(value)
|
boolVal, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -67,7 +57,8 @@ func run() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If NoColor is still unspecified, check to see if the NO_COLOR environment variable is set
|
// If NoColor is still unspecified,
|
||||||
|
// check to see if the NO_COLOR environment variable is set
|
||||||
if noColor == nil {
|
if noColor == nil {
|
||||||
noColor = new(bool)
|
noColor = new(bool)
|
||||||
if os.Getenv("NO_COLOR") != "" {
|
if os.Getenv("NO_COLOR") != "" {
|
||||||
|
@ -80,110 +71,132 @@ func run() error {
|
||||||
command := flag.Arg(0)
|
command := flag.Arg(0)
|
||||||
args := flag.Args()[1:]
|
args := flag.Args()[1:]
|
||||||
|
|
||||||
printer := printer.NewPrinter(*noColor, pager, maxTerminalWidth)
|
var (
|
||||||
|
enbasConfig *config.Config
|
||||||
|
enbasPrinter *printer.Printer
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case executor.CommandInit, executor.CommandVersion:
|
||||||
|
enbasPrinter = printer.NewPrinter(*noColor, "", 0)
|
||||||
|
default:
|
||||||
|
enbasConfig, err = config.NewConfigFromFile(configDir)
|
||||||
|
if err != nil {
|
||||||
|
enbasPrinter = printer.NewPrinter(*noColor, "", 0)
|
||||||
|
enbasPrinter.PrintFailure("unable to load the configuration: " + err.Error() + ".")
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enbasPrinter = printer.NewPrinter(*noColor, enbasConfig.Integrations.Pager, enbasConfig.LineWrapMaxWidth)
|
||||||
|
}
|
||||||
|
|
||||||
executorMap := map[string]executor.Executor{
|
executorMap := map[string]executor.Executor{
|
||||||
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandAccept,
|
executor.CommandAccept,
|
||||||
executor.CommandSummaryLookup(executor.CommandAccept),
|
executor.CommandSummaryLookup(executor.CommandAccept),
|
||||||
),
|
),
|
||||||
executor.CommandAdd: executor.NewAddExecutor(
|
executor.CommandAdd: executor.NewAddExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandAdd,
|
executor.CommandAdd,
|
||||||
executor.CommandSummaryLookup(executor.CommandAdd),
|
executor.CommandSummaryLookup(executor.CommandAdd),
|
||||||
),
|
),
|
||||||
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandBlock,
|
executor.CommandBlock,
|
||||||
executor.CommandSummaryLookup(executor.CommandBlock),
|
executor.CommandSummaryLookup(executor.CommandBlock),
|
||||||
),
|
),
|
||||||
executor.CommandCreate: executor.NewCreateExecutor(
|
executor.CommandCreate: executor.NewCreateExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandCreate,
|
executor.CommandCreate,
|
||||||
executor.CommandSummaryLookup(executor.CommandCreate),
|
executor.CommandSummaryLookup(executor.CommandCreate),
|
||||||
),
|
),
|
||||||
executor.CommandDelete: executor.NewDeleteExecutor(
|
executor.CommandDelete: executor.NewDeleteExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandDelete,
|
executor.CommandDelete,
|
||||||
executor.CommandSummaryLookup(executor.CommandDelete),
|
executor.CommandSummaryLookup(executor.CommandDelete),
|
||||||
),
|
),
|
||||||
executor.CommandEdit: executor.NewEditExecutor(
|
executor.CommandEdit: executor.NewEditExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandEdit,
|
executor.CommandEdit,
|
||||||
executor.CommandSummaryLookup(executor.CommandEdit),
|
executor.CommandSummaryLookup(executor.CommandEdit),
|
||||||
),
|
),
|
||||||
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandFollow,
|
executor.CommandFollow,
|
||||||
executor.CommandSummaryLookup(executor.CommandFollow),
|
executor.CommandSummaryLookup(executor.CommandFollow),
|
||||||
),
|
),
|
||||||
executor.CommandLogin: executor.NewLoginExecutor(
|
executor.CommandInit: executor.NewInitExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
configDir,
|
||||||
|
executor.CommandInit,
|
||||||
|
executor.CommandSummaryLookup(executor.CommandInit),
|
||||||
|
),
|
||||||
|
executor.CommandLogin: executor.NewLoginExecutor(
|
||||||
|
enbasPrinter,
|
||||||
|
enbasConfig,
|
||||||
executor.CommandLogin,
|
executor.CommandLogin,
|
||||||
executor.CommandSummaryLookup(executor.CommandLogin),
|
executor.CommandSummaryLookup(executor.CommandLogin),
|
||||||
),
|
),
|
||||||
executor.CommandMute: executor.NewMuteOrUnmuteExecutor(
|
executor.CommandMute: executor.NewMuteOrUnmuteExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandMute,
|
executor.CommandMute,
|
||||||
executor.CommandSummaryLookup(executor.CommandMute),
|
executor.CommandSummaryLookup(executor.CommandMute),
|
||||||
),
|
),
|
||||||
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandReject,
|
executor.CommandReject,
|
||||||
executor.CommandSummaryLookup(executor.CommandReject),
|
executor.CommandSummaryLookup(executor.CommandReject),
|
||||||
),
|
),
|
||||||
executor.CommandRemove: executor.NewRemoveExecutor(
|
executor.CommandRemove: executor.NewRemoveExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandRemove,
|
executor.CommandRemove,
|
||||||
executor.CommandSummaryLookup(executor.CommandRemove),
|
executor.CommandSummaryLookup(executor.CommandRemove),
|
||||||
),
|
),
|
||||||
executor.CommandSwitch: executor.NewSwitchExecutor(
|
executor.CommandSwitch: executor.NewSwitchExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandSwitch,
|
executor.CommandSwitch,
|
||||||
executor.CommandSummaryLookup(executor.CommandSwitch),
|
executor.CommandSummaryLookup(executor.CommandSwitch),
|
||||||
),
|
),
|
||||||
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandUnfollow,
|
executor.CommandUnfollow,
|
||||||
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
||||||
),
|
),
|
||||||
executor.CommandUnmute: executor.NewMuteOrUnmuteExecutor(
|
executor.CommandUnmute: executor.NewMuteOrUnmuteExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandUnmute,
|
executor.CommandUnmute,
|
||||||
executor.CommandSummaryLookup(executor.CommandUnmute),
|
executor.CommandSummaryLookup(executor.CommandUnmute),
|
||||||
),
|
),
|
||||||
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandUnblock,
|
executor.CommandUnblock,
|
||||||
executor.CommandSummaryLookup(executor.CommandUnblock),
|
executor.CommandSummaryLookup(executor.CommandUnblock),
|
||||||
),
|
),
|
||||||
executor.CommandShow: executor.NewShowExecutor(
|
executor.CommandShow: executor.NewShowExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
cacheDir,
|
|
||||||
imageViewer,
|
|
||||||
videoPlayer,
|
|
||||||
executor.CommandShow,
|
executor.CommandShow,
|
||||||
executor.CommandSummaryLookup(executor.CommandShow),
|
executor.CommandSummaryLookup(executor.CommandShow),
|
||||||
),
|
),
|
||||||
executor.CommandVersion: executor.NewVersionExecutor(
|
executor.CommandVersion: executor.NewVersionExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
executor.CommandVersion,
|
executor.CommandVersion,
|
||||||
executor.CommandSummaryLookup(executor.CommandVersion),
|
executor.CommandSummaryLookup(executor.CommandVersion),
|
||||||
binaryVersion,
|
binaryVersion,
|
||||||
|
@ -192,8 +205,8 @@ func run() error {
|
||||||
gitCommit,
|
gitCommit,
|
||||||
),
|
),
|
||||||
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
||||||
printer,
|
enbasPrinter,
|
||||||
configDir,
|
enbasConfig,
|
||||||
executor.CommandWhoami,
|
executor.CommandWhoami,
|
||||||
executor.CommandSummaryLookup(executor.CommandWhoami),
|
executor.CommandSummaryLookup(executor.CommandWhoami),
|
||||||
),
|
),
|
||||||
|
@ -201,16 +214,16 @@ func run() error {
|
||||||
|
|
||||||
exe, ok := executorMap[command]
|
exe, ok := executorMap[command]
|
||||||
if !ok {
|
if !ok {
|
||||||
err := executor.UnknownCommandError{Command: command}
|
err = executor.UnknownCommandError{Command: command}
|
||||||
|
|
||||||
printer.PrintFailure(err.Error() + ".")
|
enbasPrinter.PrintFailure(err.Error() + ".")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := executor.Execute(exe, args); err != nil {
|
if err = executor.Execute(exe, args); err != nil {
|
||||||
printer.PrintFailure("(" + command + ") " + err.Error() + ".")
|
enbasPrinter.PrintFailure("(" + command + ") " + err.Error() + ".")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ type Client struct {
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientFromConfig(configDir string) (*Client, error) {
|
func NewClientFromFile(path string) (*Client, error) {
|
||||||
config, err := config.NewCredentialsConfigFromFile(configDir)
|
config, err := config.NewCredentialsConfigFromFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to get the authentication configuration: %w", err)
|
return nil, fmt.Errorf("unable to get the authentication configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func NewClient(authentication config.Credentials) *Client {
|
||||||
|
|
||||||
func (g *Client) AuthCodeURL() string {
|
func (g *Client) AuthCodeURL() string {
|
||||||
format := "%s/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code"
|
format := "%s/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code"
|
||||||
escapedRedirectURI := url.QueryEscape(internal.RedirectUri)
|
escapedRedirectURI := url.QueryEscape(internal.RedirectURI)
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
format,
|
format,
|
||||||
|
|
|
@ -24,7 +24,7 @@ type registerRequest struct {
|
||||||
func (g *Client) Register() error {
|
func (g *Client) Register() error {
|
||||||
params := registerRequest{
|
params := registerRequest{
|
||||||
ClientName: internal.ApplicationName,
|
ClientName: internal.ApplicationName,
|
||||||
RedirectUris: internal.RedirectUri,
|
RedirectUris: internal.RedirectURI,
|
||||||
Scopes: "read write",
|
Scopes: "read write",
|
||||||
Website: internal.ApplicationWebsite,
|
Website: internal.ApplicationWebsite,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
var errEmptyAccessToken = errors.New("received an empty access token")
|
var errEmptyAccessToken = errors.New("received an empty access token")
|
||||||
|
|
||||||
type tokenRequest struct {
|
type tokenRequest struct {
|
||||||
RedirectUri string `json:"redirect_uri"`
|
RedirectURI string `json:"redirect_uri"`
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
GrantType string `json:"grant_type"`
|
GrantType string `json:"grant_type"`
|
||||||
|
@ -33,7 +33,7 @@ type tokenResponse struct {
|
||||||
|
|
||||||
func (g *Client) UpdateToken(code string) error {
|
func (g *Client) UpdateToken(code string) error {
|
||||||
params := tokenRequest{
|
params := tokenRequest{
|
||||||
RedirectUri: internal.RedirectUri,
|
RedirectURI: internal.RedirectURI,
|
||||||
ClientID: g.Authentication.ClientID,
|
ClientID: g.Authentication.ClientID,
|
||||||
ClientSecret: g.Authentication.ClientSecret,
|
ClientSecret: g.Authentication.ClientSecret,
|
||||||
GrantType: "authorization_code",
|
GrantType: "authorization_code",
|
||||||
|
|
108
internal/config/config.go
Normal file
108
internal/config/config.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
configFileName = "config.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
CredentialsFile string `json:"credentialsFile"`
|
||||||
|
CacheDirectory string `json:"cacheDirectory"`
|
||||||
|
LineWrapMaxWidth int `json:"lineWrapMaxWidth"`
|
||||||
|
HTTP HTTPConfig `json:"http"`
|
||||||
|
Integrations Integrations `json:"integrations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPConfig struct {
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
MediaTimeout int `json:"mediaTimeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Integrations struct {
|
||||||
|
Browser string `json:"browser"`
|
||||||
|
Editor string `json:"editor"`
|
||||||
|
Pager string `json:"pager"`
|
||||||
|
ImageViewer string `json:"imageViewer"`
|
||||||
|
VideoPlayer string `json:"videoPlayer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigFromFile(configDir string) (*Config, error) {
|
||||||
|
path := configFile(configDir)
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to open %s: %w", path, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var config Config
|
||||||
|
|
||||||
|
if err := json.NewDecoder(file).Decode(&config); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to decode the JSON data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FileExists(configDir string) (bool, error) {
|
||||||
|
path := configFile(configDir)
|
||||||
|
|
||||||
|
return utilities.FileExists(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveDefaultConfigToFile(configDir string) error {
|
||||||
|
path := configFile(configDir)
|
||||||
|
|
||||||
|
file, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create the file at %s: %w", path, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
config := defaultConfig(configDir)
|
||||||
|
encoder := json.NewEncoder(file)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
|
||||||
|
if err := encoder.Encode(config); err != nil {
|
||||||
|
return fmt.Errorf("unable to save the JSON data to the config file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configFile(configDir string) string {
|
||||||
|
return filepath.Join(utilities.CalculateConfigDir(configDir), configFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultConfig(configDir string) Config {
|
||||||
|
credentialsFilePath := defaultCredentialsConfigFile(configDir)
|
||||||
|
|
||||||
|
return Config{
|
||||||
|
CredentialsFile: credentialsFilePath,
|
||||||
|
CacheDirectory: "",
|
||||||
|
HTTP: HTTPConfig{
|
||||||
|
Timeout: 5,
|
||||||
|
MediaTimeout: 30,
|
||||||
|
},
|
||||||
|
LineWrapMaxWidth: 80,
|
||||||
|
Integrations: Integrations{
|
||||||
|
Browser: "",
|
||||||
|
Editor: "",
|
||||||
|
Pager: "",
|
||||||
|
ImageViewer: "",
|
||||||
|
VideoPlayer: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
credentialsFileName = "credentials.json"
|
defaultCredentialsFileName = "credentials.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CredentialsConfig struct {
|
type CredentialsConfig struct {
|
||||||
|
@ -42,35 +41,29 @@ func (e CredentialsNotFoundError) Error() string {
|
||||||
// SaveCredentials saves the credentials into the credentials file within the specified configuration
|
// SaveCredentials saves the credentials into the credentials file within the specified configuration
|
||||||
// directory. If the directory is not specified then the default directory is used. If the directory
|
// directory. If the directory is not specified then the default directory is used. If the directory
|
||||||
// is not present, it will be created.
|
// is not present, it will be created.
|
||||||
func SaveCredentials(configDir, username string, credentials Credentials) (string, error) {
|
func SaveCredentials(filePath, username string, credentials Credentials) (string, error) {
|
||||||
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(configDir)); err != nil {
|
directory := filepath.Dir(filePath)
|
||||||
|
|
||||||
|
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(directory)); err != nil {
|
||||||
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
|
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var authConfig CredentialsConfig
|
var authConfig CredentialsConfig
|
||||||
|
|
||||||
filepath := credentialsConfigFile(configDir)
|
if _, err := os.Stat(filePath); err != nil {
|
||||||
|
|
||||||
if _, err := os.Stat(filepath); err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
return "", fmt.Errorf("unknown error received when running stat on %s: %w", filepath, err)
|
return "", fmt.Errorf("unknown error received when running stat on %s: %w", filePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
authConfig.Credentials = make(map[string]Credentials)
|
authConfig.Credentials = make(map[string]Credentials)
|
||||||
} else {
|
} else {
|
||||||
authConfig, err = NewCredentialsConfigFromFile(configDir)
|
authConfig, err = NewCredentialsConfigFromFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instance := ""
|
instance := utilities.GetFQDN(credentials.Instance)
|
||||||
|
|
||||||
if strings.HasPrefix(credentials.Instance, "https://") {
|
|
||||||
instance = strings.TrimPrefix(credentials.Instance, "https://")
|
|
||||||
} else if strings.HasPrefix(credentials.Instance, "http://") {
|
|
||||||
instance = strings.TrimPrefix(credentials.Instance, "http://")
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticationName := username + "@" + instance
|
authenticationName := username + "@" + instance
|
||||||
|
|
||||||
|
@ -78,15 +71,15 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
|
||||||
|
|
||||||
authConfig.Credentials[authenticationName] = credentials
|
authConfig.Credentials[authenticationName] = credentials
|
||||||
|
|
||||||
if err := saveCredentialsConfigFile(authConfig, configDir); err != nil {
|
if err := saveCredentialsConfigFile(authConfig, filePath); err != nil {
|
||||||
return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return authenticationName, nil
|
return authenticationName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateCurrentAccount(account string, configDir string) error {
|
func UpdateCurrentAccount(account string, filePath string) error {
|
||||||
credentialsConfig, err := NewCredentialsConfigFromFile(configDir)
|
credentialsConfig, err := NewCredentialsConfigFromFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -97,19 +90,19 @@ func UpdateCurrentAccount(account string, configDir string) error {
|
||||||
|
|
||||||
credentialsConfig.CurrentAccount = account
|
credentialsConfig.CurrentAccount = account
|
||||||
|
|
||||||
if err := saveCredentialsConfigFile(credentialsConfig, configDir); err != nil {
|
if err := saveCredentialsConfigFile(credentialsConfig, filePath); err != nil {
|
||||||
return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
|
// NewCredentialsConfigFromFile creates a new CredentialsConfig value from reading
|
||||||
path := credentialsConfigFile(configDir)
|
// the credentials file.
|
||||||
|
func NewCredentialsConfigFromFile(filePath string) (CredentialsConfig, error) {
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return CredentialsConfig{}, fmt.Errorf("unable to open %s, %w", path, err)
|
return CredentialsConfig{}, fmt.Errorf("unable to open %s: %w", filePath, err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
@ -122,14 +115,11 @@ func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
|
||||||
return authConfig, nil
|
return authConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) error {
|
func saveCredentialsConfigFile(authConfig CredentialsConfig, filePath string) error {
|
||||||
path := credentialsConfigFile(configDir)
|
file, err := os.Create(filePath)
|
||||||
|
|
||||||
file, err := os.Create(path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to open %s: %w", path, err)
|
return fmt.Errorf("unable to create the file at %s: %w", filePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
encoder := json.NewEncoder(file)
|
encoder := json.NewEncoder(file)
|
||||||
|
@ -142,6 +132,6 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func credentialsConfigFile(configDir string) string {
|
func defaultCredentialsConfigFile(configDir string) string {
|
||||||
return filepath.Join(utilities.CalculateConfigDir(configDir), credentialsFileName)
|
return filepath.Join(utilities.CalculateConfigDir(configDir), defaultCredentialsFileName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,19 +17,19 @@ type AcceptOrRejectExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
command string
|
command string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, configDir, name, summary string) *AcceptOrRejectExecutor {
|
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, config *config.Config, name, summary string) *AcceptOrRejectExecutor {
|
||||||
acceptExe := AcceptOrRejectExecutor{
|
acceptExe := AcceptOrRejectExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: enbasPrinter,
|
printer: enbasPrinter,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
command: name,
|
command: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptExe.StringVar(&acceptExe.resourceType, flagType, "", "Specify the type of resource to accept or reject")
|
acceptExe.StringVar(&acceptExe.resourceType, flagType, "", "Specify the type of resource to accept or reject")
|
||||||
|
@ -49,7 +50,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: a.resourceType}
|
return UnsupportedTypeError{resourceType: a.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -58,7 +59,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AcceptOrRejectExecutor) acceptOrRejectFollowRequest(gtsClient *client.Client) error {
|
func (a *AcceptOrRejectExecutor) acceptOrRejectFollowRequest(gtsClient *client.Client) error {
|
||||||
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
|
accountID, err := getAccountID(gtsClient, false, a.accountName, a.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configDir string) (string, error) {
|
func getAccountID(gtsClient *client.Client, myAccount bool, accountName, path string) (string, error) {
|
||||||
var (
|
var (
|
||||||
accountID string
|
accountID string
|
||||||
err error
|
err error
|
||||||
|
@ -20,7 +20,7 @@ func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configD
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case myAccount:
|
case myAccount:
|
||||||
accountID, err = getMyAccountID(gtsClient, configDir)
|
accountID, err = getMyAccountID(gtsClient, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("unable to get your account ID: %w", err)
|
return "", fmt.Errorf("unable to get your account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, err
|
||||||
return account.ID, nil
|
return account.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMyAccountID(gtsClient *client.Client, configDir string) (string, error) {
|
func getMyAccountID(gtsClient *client.Client, path string) (string, error) {
|
||||||
account, err := getMyAccount(gtsClient, configDir)
|
account, err := getMyAccount(gtsClient, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("received an error while getting your account details: %w", err)
|
return "", fmt.Errorf("received an error while getting your account details: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,8 @@ func getMyAccountID(gtsClient *client.Client, configDir string) (string, error)
|
||||||
return account.ID, nil
|
return account.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, error) {
|
func getMyAccount(gtsClient *client.Client, path string) (model.Account, error) {
|
||||||
authConfig, err := config.NewCredentialsConfigFromFile(configDir)
|
authConfig, err := config.NewCredentialsConfigFromFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration: %w", err)
|
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ type AddExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
toResourceType string
|
toResourceType string
|
||||||
listID string
|
listID string
|
||||||
|
@ -28,14 +29,14 @@ type AddExecutor struct {
|
||||||
content string
|
content string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAddExecutor(printer *printer.Printer, configDir, name, summary string) *AddExecutor {
|
func NewAddExecutor(printer *printer.Printer, config *config.Config, name, summary string) *AddExecutor {
|
||||||
emptyArr := make([]string, 0, 3)
|
emptyArr := make([]string, 0, 3)
|
||||||
|
|
||||||
addExe := AddExecutor{
|
addExe := AddExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
accountNames: MultiStringFlagValue(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ func (a *AddExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: a.toResourceType}
|
return UnsupportedTypeError{resourceType: a.toResourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +155,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames))
|
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames))
|
||||||
}
|
}
|
||||||
|
|
||||||
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
|
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,19 +17,19 @@ type BlockOrUnblockExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
command string
|
command string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockOrUnblockExecutor(printer *printer.Printer, configDir, name, summary string) *BlockOrUnblockExecutor {
|
func NewBlockOrUnblockExecutor(printer *printer.Printer, config *config.Config, name, summary string) *BlockOrUnblockExecutor {
|
||||||
blockExe := BlockOrUnblockExecutor{
|
blockExe := BlockOrUnblockExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
command: name,
|
command: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
blockExe.StringVar(&blockExe.resourceType, flagType, "", "Specify the type of resource to block or unblock")
|
blockExe.StringVar(&blockExe.resourceType, flagType, "", "Specify the type of resource to block or unblock")
|
||||||
|
@ -49,7 +50,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: b.resourceType}
|
return UnsupportedTypeError{resourceType: b.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(b.configDir)
|
gtsClient, err := client.NewClientFromFile(b.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ func (b *BlockOrUnblockExecutor) blockOrUnblockAccount(gtsClient *client.Client)
|
||||||
return FlagNotSetError{flagText: flagAccountName}
|
return FlagNotSetError{flagText: flagAccountName}
|
||||||
}
|
}
|
||||||
|
|
||||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
|
accountID, err := getAccountID(gtsClient, false, b.accountName, b.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ const (
|
||||||
CommandDelete string = "delete"
|
CommandDelete string = "delete"
|
||||||
CommandEdit string = "edit"
|
CommandEdit string = "edit"
|
||||||
CommandFollow string = "follow"
|
CommandFollow string = "follow"
|
||||||
|
CommandInit string = "init"
|
||||||
CommandLogin string = "login"
|
CommandLogin string = "login"
|
||||||
CommandMute string = "mute"
|
CommandMute string = "mute"
|
||||||
CommandReject string = "reject"
|
CommandReject string = "reject"
|
||||||
|
@ -31,6 +32,7 @@ const (
|
||||||
commandDeleteSummary string = "Delete a specific resource"
|
commandDeleteSummary string = "Delete a specific resource"
|
||||||
commandEditSummary string = "Edit a specific resource"
|
commandEditSummary string = "Edit a specific resource"
|
||||||
commandFollowSummary string = "Follow a resource (e.g. an account)"
|
commandFollowSummary string = "Follow a resource (e.g. an account)"
|
||||||
|
commandInitSummary string = "Create a new configuration file in the specified configuration directory"
|
||||||
commandLoginSummary string = "Login to an account on GoToSocial"
|
commandLoginSummary string = "Login to an account on GoToSocial"
|
||||||
commandMuteSummary string = "Mute a resource (e.g. an account)"
|
commandMuteSummary string = "Mute a resource (e.g. an account)"
|
||||||
commandRejectSummary string = "Reject a request (e.g. a follow request)"
|
commandRejectSummary string = "Reject a request (e.g. a follow request)"
|
||||||
|
@ -53,6 +55,7 @@ func CommandSummaryMap() map[string]string {
|
||||||
CommandDelete: commandDeleteSummary,
|
CommandDelete: commandDeleteSummary,
|
||||||
CommandEdit: commandEditSummary,
|
CommandEdit: commandEditSummary,
|
||||||
CommandFollow: commandFollowSummary,
|
CommandFollow: commandFollowSummary,
|
||||||
|
CommandInit: commandInitSummary,
|
||||||
CommandLogin: commandLoginSummary,
|
CommandLogin: commandLoginSummary,
|
||||||
CommandMute: commandMuteSummary,
|
CommandMute: commandMuteSummary,
|
||||||
CommandReject: commandRejectSummary,
|
CommandReject: commandRejectSummary,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
@ -19,6 +20,7 @@ type CreateExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
|
config *config.Config
|
||||||
addPoll bool
|
addPoll bool
|
||||||
boostable bool
|
boostable bool
|
||||||
federated bool
|
federated bool
|
||||||
|
@ -27,7 +29,6 @@ type CreateExecutor struct {
|
||||||
pollHidesVoteCounts bool
|
pollHidesVoteCounts bool
|
||||||
replyable bool
|
replyable bool
|
||||||
sensitive *bool
|
sensitive *bool
|
||||||
configDir string
|
|
||||||
content string
|
content string
|
||||||
contentType string
|
contentType string
|
||||||
fromFile string
|
fromFile string
|
||||||
|
@ -41,12 +42,12 @@ type CreateExecutor struct {
|
||||||
pollOptions MultiStringFlagValue
|
pollOptions MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateExecutor(printer *printer.Printer, configDir, name, summary string) *CreateExecutor {
|
func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, summary string) *CreateExecutor {
|
||||||
createExe := CreateExecutor{
|
createExe := CreateExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
createExe.BoolVar(&createExe.boostable, flagEnableReposts, true, "Specify if the status can be reposted/boosted by others")
|
createExe.BoolVar(&createExe.boostable, flagEnableReposts, true, "Specify if the status can be reposted/boosted by others")
|
||||||
|
@ -90,7 +91,7 @@ func (c *CreateExecutor) Execute() error {
|
||||||
return FlagNotSetError{flagText: flagType}
|
return FlagNotSetError{flagText: flagType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(c.configDir)
|
gtsClient, err := client.NewClientFromFile(c.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,17 +17,17 @@ type DeleteExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
listID string
|
listID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDeleteExecutor(printer *printer.Printer, configDir, name, summary string) *DeleteExecutor {
|
func NewDeleteExecutor(printer *printer.Printer, config *config.Config, name, summary string) *DeleteExecutor {
|
||||||
deleteExe := DeleteExecutor{
|
deleteExe := DeleteExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
|
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
|
||||||
|
@ -51,7 +52,7 @@ func (d *DeleteExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: d.resourceType}
|
return UnsupportedTypeError{resourceType: d.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(d.configDir)
|
gtsClient, err := client.NewClientFromFile(d.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
@ -17,19 +18,19 @@ type EditExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
listID string
|
listID string
|
||||||
listTitle string
|
listTitle string
|
||||||
listRepliesPolicy string
|
listRepliesPolicy string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditExecutor(printer *printer.Printer, configDir, name, summary string) *EditExecutor {
|
func NewEditExecutor(printer *printer.Printer, config *config.Config, name, summary string) *EditExecutor {
|
||||||
editExe := EditExecutor{
|
editExe := EditExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
|
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
|
||||||
|
@ -56,7 +57,7 @@ func (e *EditExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: e.resourceType}
|
return UnsupportedTypeError{resourceType: e.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(e.configDir)
|
gtsClient, err := client.NewClientFromFile(e.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,3 +102,11 @@ type NotFollowingError struct {
|
||||||
func (e NotFollowingError) Error() string {
|
func (e NotFollowingError) Error() string {
|
||||||
return "you are not following " + e.Account
|
return "you are not following " + e.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnknownMediaAttachmentError struct {
|
||||||
|
AttachmentID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnknownMediaAttachmentError) Error() string {
|
||||||
|
return "unknown media attachment '" + e.AttachmentID + "'"
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ type FollowOrUnfollowExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
showReposts bool
|
showReposts bool
|
||||||
|
@ -24,13 +25,13 @@ type FollowOrUnfollowExecutor struct {
|
||||||
action string
|
action string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFollowOrUnfollowExecutor(printer *printer.Printer, configDir, name, summary string) *FollowOrUnfollowExecutor {
|
func NewFollowOrUnfollowExecutor(printer *printer.Printer, config *config.Config, name, summary string) *FollowOrUnfollowExecutor {
|
||||||
command := FollowOrUnfollowExecutor{
|
command := FollowOrUnfollowExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
action: name,
|
action: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
command.StringVar(&command.resourceType, flagType, "", "Specify the type of resource to follow")
|
command.StringVar(&command.resourceType, flagType, "", "Specify the type of resource to follow")
|
||||||
|
@ -53,7 +54,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: f.resourceType}
|
return UnsupportedTypeError{resourceType: f.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(f.configDir)
|
gtsClient, err := client.NewClientFromFile(f.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FollowOrUnfollowExecutor) followOrUnfollowAccount(gtsClient *client.Client) error {
|
func (f *FollowOrUnfollowExecutor) followOrUnfollowAccount(gtsClient *client.Client) error {
|
||||||
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
|
accountID, err := getAccountID(gtsClient, false, f.accountName, f.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
61
internal/executor/init.go
Normal file
61
internal/executor/init.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InitExecutor struct {
|
||||||
|
*flag.FlagSet
|
||||||
|
|
||||||
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInitExecutor(printer *printer.Printer, configDir, name, summary string) *InitExecutor {
|
||||||
|
initExe := InitExecutor{
|
||||||
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
initExe.Usage = commandUsageFunc(name, summary, initExe.FlagSet)
|
||||||
|
|
||||||
|
return &initExe
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *InitExecutor) Execute() error {
|
||||||
|
if err := utilities.EnsureDirectory(i.configDir); err != nil {
|
||||||
|
return fmt.Errorf("unable to ensure that the configuration directory is present: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i.printer.PrintSuccess("The configuration directory is present.")
|
||||||
|
|
||||||
|
fileExists, err := config.FileExists(i.configDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to check if the config file exists: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fileExists {
|
||||||
|
i.printer.PrintInfo("The configuration file is already present in " + i.configDir + "\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.SaveDefaultConfigToFile(i.configDir); err != nil {
|
||||||
|
return fmt.Errorf("unable to create a new configuration file in %s: %w", i.configDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i.printer.PrintSuccess("Successfully created a new configuration file in " + i.configDir)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -18,18 +18,18 @@ import (
|
||||||
type LoginExecutor struct {
|
type LoginExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
instance string
|
instance string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoginExecutor(printer *printer.Printer, configDir, name, summary string) *LoginExecutor {
|
func NewLoginExecutor(printer *printer.Printer, config *config.Config, name, summary string) *LoginExecutor {
|
||||||
command := LoginExecutor{
|
command := LoginExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
instance: "",
|
instance: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
command.StringVar(&command.instance, flagInstance, "", "Specify the instance that you want to login to.")
|
command.StringVar(&command.instance, flagInstance, "", "Specify the instance that you want to login to.")
|
||||||
|
@ -95,7 +95,7 @@ func (c *LoginExecutor) Execute() error {
|
||||||
return fmt.Errorf("unable to verify the credentials: %w", err)
|
return fmt.Errorf("unable to verify the credentials: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
loginName, err := config.SaveCredentials(c.configDir, account.Username, gtsClient.Authentication)
|
loginName, err := config.SaveCredentials(c.config.CredentialsFile, account.Username, gtsClient.Authentication)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save the authentication details: %w", err)
|
return fmt.Errorf("unable to save the authentication details: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,21 +17,21 @@ type MuteOrUnmuteExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
|
config *config.Config
|
||||||
accountName string
|
accountName string
|
||||||
configDir string
|
|
||||||
command string
|
command string
|
||||||
resourceType string
|
resourceType string
|
||||||
muteDuration TimeDurationFlagValue
|
muteDuration TimeDurationFlagValue
|
||||||
muteNotifications bool
|
muteNotifications bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMuteOrUnmuteExecutor(printer *printer.Printer, configDir, name, summary string) *MuteOrUnmuteExecutor {
|
func NewMuteOrUnmuteExecutor(printer *printer.Printer, config *config.Config, name, summary string) *MuteOrUnmuteExecutor {
|
||||||
exe := MuteOrUnmuteExecutor{
|
exe := MuteOrUnmuteExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
command: name,
|
command: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
exe.StringVar(&exe.accountName, flagAccountName, "", "Specify the account name in full (username@domain)")
|
exe.StringVar(&exe.accountName, flagAccountName, "", "Specify the account name in full (username@domain)")
|
||||||
|
@ -53,7 +54,7 @@ func (m *MuteOrUnmuteExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: m.resourceType}
|
return UnsupportedTypeError{resourceType: m.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(m.configDir)
|
gtsClient, err := client.NewClientFromFile(m.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,7 @@ func (m *MuteOrUnmuteExecutor) muteOrUnmuteAccount(gtsClient *client.Client) err
|
||||||
return FlagNotSetError{flagText: flagAccountName}
|
return FlagNotSetError{flagText: flagAccountName}
|
||||||
}
|
}
|
||||||
|
|
||||||
accountID, err := getAccountID(gtsClient, false, m.accountName, m.configDir)
|
accountID, err := getAccountID(gtsClient, false, m.accountName, m.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ type RemoveExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
resourceType string
|
resourceType string
|
||||||
fromResourceType string
|
fromResourceType string
|
||||||
listID string
|
listID string
|
||||||
|
@ -24,14 +25,14 @@ type RemoveExecutor struct {
|
||||||
accountNames MultiStringFlagValue
|
accountNames MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoveExecutor(printer *printer.Printer, configDir, name, summary string) *RemoveExecutor {
|
func NewRemoveExecutor(printer *printer.Printer, config *config.Config, name, summary string) *RemoveExecutor {
|
||||||
emptyArr := make([]string, 0, 3)
|
emptyArr := make([]string, 0, 3)
|
||||||
|
|
||||||
removeExe := RemoveExecutor{
|
removeExe := RemoveExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
accountNames: MultiStringFlagValue(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ func (r *RemoveExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: r.fromResourceType}
|
return UnsupportedTypeError{resourceType: r.fromResourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(r.configDir)
|
gtsClient, err := client.NewClientFromFile(r.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(r.accountNames))
|
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(r.accountNames))
|
||||||
}
|
}
|
||||||
|
|
||||||
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.configDir)
|
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
@ -20,12 +21,11 @@ type ShowExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
|
config *config.Config
|
||||||
myAccount bool
|
myAccount bool
|
||||||
skipAccountRelationship bool
|
skipAccountRelationship bool
|
||||||
showUserPreferences bool
|
showUserPreferences bool
|
||||||
showInBrowser bool
|
showInBrowser bool
|
||||||
configDir string
|
|
||||||
cacheRoot string
|
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
statusID string
|
statusID string
|
||||||
|
@ -34,21 +34,16 @@ type ShowExecutor struct {
|
||||||
tag string
|
tag string
|
||||||
pollID string
|
pollID string
|
||||||
fromResourceType string
|
fromResourceType string
|
||||||
imageViewer string
|
|
||||||
videoPlayer string
|
|
||||||
limit int
|
limit int
|
||||||
attachmentIDs MultiStringFlagValue
|
attachmentIDs MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShowExecutor(printer *printer.Printer, configDir, cacheRoot, imageViewer, videoPlayer, name, summary string) *ShowExecutor {
|
func NewShowExecutor(printer *printer.Printer, config *config.Config, name, summary string) *ShowExecutor {
|
||||||
showExe := ShowExecutor{
|
showExe := ShowExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
cacheRoot: cacheRoot,
|
|
||||||
imageViewer: imageViewer,
|
|
||||||
videoPlayer: videoPlayer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
|
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
|
||||||
|
@ -100,7 +95,7 @@ func (s *ShowExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: s.resourceType}
|
return UnsupportedTypeError{resourceType: s.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(s.configDir)
|
gtsClient, err := client.NewClientFromFile(s.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -126,7 +121,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
||||||
)
|
)
|
||||||
|
|
||||||
if s.myAccount {
|
if s.myAccount {
|
||||||
account, err = getMyAccount(gtsClient, s.configDir)
|
account, err = getMyAccount(gtsClient, s.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account details: %w", err)
|
return fmt.Errorf("received an error while getting the account details: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -288,7 +283,7 @@ func (s *ShowExecutor) showLists(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
|
func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
|
||||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -308,7 +303,7 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
|
func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
|
||||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -471,7 +466,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheDir := filepath.Join(
|
cacheDir := filepath.Join(
|
||||||
utilities.CalculateCacheDir(s.cacheRoot, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
utilities.CalculateCacheDir(s.config.CacheDirectory, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
||||||
"media",
|
"media",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -498,7 +493,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
for _, attachmentID := range s.attachmentIDs {
|
for _, attachmentID := range s.attachmentIDs {
|
||||||
mediaObj, ok := attachmentsHashMap[attachmentID]
|
mediaObj, ok := attachmentsHashMap[attachmentID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown media attachment: %s", attachmentID)
|
return UnknownMediaAttachmentError{AttachmentID: attachmentID}
|
||||||
}
|
}
|
||||||
|
|
||||||
split := strings.Split(mediaObj.url, "/")
|
split := strings.Split(mediaObj.url, "/")
|
||||||
|
@ -533,13 +528,13 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(imageFiles) > 0 {
|
if len(imageFiles) > 0 {
|
||||||
if err := utilities.OpenMedia(s.imageViewer, imageFiles); err != nil {
|
if err := utilities.OpenMedia(s.config.Integrations.ImageViewer, imageFiles); err != nil {
|
||||||
return fmt.Errorf("unable to open the image viewer: %w", err)
|
return fmt.Errorf("unable to open the image viewer: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(videoFiles) > 0 {
|
if len(videoFiles) > 0 {
|
||||||
if err := utilities.OpenMedia(s.videoPlayer, videoFiles); err != nil {
|
if err := utilities.OpenMedia(s.config.Integrations.VideoPlayer, videoFiles); err != nil {
|
||||||
return fmt.Errorf("unable to open the video player: %w", err)
|
return fmt.Errorf("unable to open the video player: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,17 @@ import (
|
||||||
type SwitchExecutor struct {
|
type SwitchExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
configDir string
|
config *config.Config
|
||||||
toResourceType string
|
toResourceType string
|
||||||
accountName string
|
accountName string
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSwitchExecutor(printer *printer.Printer, configDir, name, summary string) *SwitchExecutor {
|
func NewSwitchExecutor(printer *printer.Printer, config *config.Config, name, summary string) *SwitchExecutor {
|
||||||
switchExe := SwitchExecutor{
|
switchExe := SwitchExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
||||||
|
@ -54,7 +54,7 @@ func (s *SwitchExecutor) switchToAccount() error {
|
||||||
return NoAccountSpecifiedError{}
|
return NoAccountSpecifiedError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.UpdateCurrentAccount(s.accountName, s.configDir); err != nil {
|
if err := config.UpdateCurrentAccount(s.accountName, s.config.CredentialsFile); err != nil {
|
||||||
return fmt.Errorf("unable to switch account to the account: %w", err)
|
return fmt.Errorf("unable to switch account to the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ package executor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,27 +15,41 @@ func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
|
||||||
return func() {
|
return func() {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
fmt.Fprintf(
|
builder.WriteString("SUMMARY:")
|
||||||
&builder,
|
builder.WriteString("\n " + name + " - " + summary)
|
||||||
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
|
builder.WriteString("\n\nUSAGE:")
|
||||||
name,
|
builder.WriteString("\n enbas " + name)
|
||||||
summary,
|
|
||||||
name,
|
flagMap := make(map[string]string)
|
||||||
)
|
|
||||||
|
|
||||||
flagset.VisitAll(func(f *flag.Flag) {
|
flagset.VisitAll(func(f *flag.Flag) {
|
||||||
fmt.Fprintf(
|
flagMap[f.Name] = f.Usage
|
||||||
&builder,
|
|
||||||
"\n --%s\n %s",
|
|
||||||
f.Name,
|
|
||||||
f.Usage,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if len(flagMap) > 0 {
|
||||||
|
flags := make([]string, len(flagMap))
|
||||||
|
ind := 0
|
||||||
|
|
||||||
|
for f := range flagMap {
|
||||||
|
flags[ind] = f
|
||||||
|
ind++
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.Sort(flags)
|
||||||
|
|
||||||
|
builder.WriteString(" [flags]")
|
||||||
|
builder.WriteString("\n\nFLAGS:")
|
||||||
|
|
||||||
|
for _, value := range flags {
|
||||||
|
builder.WriteString("\n --" + value)
|
||||||
|
builder.WriteString("\n " + flagMap[value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
builder.WriteString("\n")
|
builder.WriteString("\n")
|
||||||
|
|
||||||
w := flag.CommandLine.Output()
|
w := flag.CommandLine.Output()
|
||||||
|
|
||||||
fmt.Fprint(w, builder.String())
|
_, _ = w.Write([]byte(builder.String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
type VersionExecutor struct {
|
type VersionExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
showFullVersion bool
|
showFullVersion bool
|
||||||
binaryVersion string
|
binaryVersion string
|
||||||
|
@ -21,7 +22,7 @@ type VersionExecutor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVersionExecutor(
|
func NewVersionExecutor(
|
||||||
enbasPrinter *printer.Printer,
|
printer *printer.Printer,
|
||||||
name,
|
name,
|
||||||
summary,
|
summary,
|
||||||
binaryVersion,
|
binaryVersion,
|
||||||
|
@ -32,7 +33,7 @@ func NewVersionExecutor(
|
||||||
command := VersionExecutor{
|
command := VersionExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: enbasPrinter,
|
printer: printer,
|
||||||
binaryVersion: binaryVersion,
|
binaryVersion: binaryVersion,
|
||||||
buildTime: buildTime,
|
buildTime: buildTime,
|
||||||
goVersion: goVersion,
|
goVersion: goVersion,
|
||||||
|
|
|
@ -15,16 +15,16 @@ import (
|
||||||
type WhoAmIExecutor struct {
|
type WhoAmIExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
configDir string
|
config *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string) *WhoAmIExecutor {
|
func NewWhoAmIExecutor(printer *printer.Printer, config *config.Config, name, summary string) *WhoAmIExecutor {
|
||||||
whoExe := WhoAmIExecutor{
|
whoExe := WhoAmIExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
printer: printer,
|
printer: printer,
|
||||||
configDir: configDir,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
|
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
|
||||||
|
@ -33,7 +33,7 @@ func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WhoAmIExecutor) Execute() error {
|
func (c *WhoAmIExecutor) Execute() error {
|
||||||
config, err := config.NewCredentialsConfigFromFile(c.configDir)
|
config, err := config.NewCredentialsConfigFromFile(c.config.CredentialsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load the credential config: %w", err)
|
return fmt.Errorf("unable to load the credential config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,6 @@ package internal
|
||||||
const (
|
const (
|
||||||
ApplicationName = "enbas"
|
ApplicationName = "enbas"
|
||||||
ApplicationWebsite = "https://codeflow.dananglin.me.uk/apollo/enbas"
|
ApplicationWebsite = "https://codeflow.dananglin.me.uk/apollo/enbas"
|
||||||
RedirectUri = "urn:ietf:wg:oauth:2.0:oob"
|
RedirectURI = "urn:ietf:wg:oauth:2.0:oob"
|
||||||
UserAgent = "Enbas/0.0.0"
|
UserAgent = "Enbas/0.0.0"
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,7 @@ type Application struct {
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
RedirectUri string `json:"redirect_uri"`
|
RedirectURI string `json:"redirect_uri"`
|
||||||
VapidKey string `json:"vapid_key"`
|
VapidKey string `json:"vapid_key"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ type InstanceV2Thumbnail struct {
|
||||||
ThumbnailDescription string `json:"thumbnail_description"`
|
ThumbnailDescription string `json:"thumbnail_description"`
|
||||||
ThumbnailType string `json:"thumbnail_type"`
|
ThumbnailType string `json:"thumbnail_type"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Versions InstanceV2ThumbnailVersions `json:"versions"`
|
Versions InstanceV2ThumbnailVersions `json:"versions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type InstanceV2ThumbnailVersions struct {
|
type InstanceV2ThumbnailVersions struct {
|
||||||
|
|
|
@ -20,7 +20,7 @@ func CalculateConfigDir(configDir string) string {
|
||||||
|
|
||||||
configRoot, err := os.UserConfigDir()
|
configRoot, err := os.UserConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
configRoot = "."
|
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "config")
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Join(configRoot, internal.ApplicationName)
|
return filepath.Join(configRoot, internal.ApplicationName)
|
||||||
|
@ -33,7 +33,7 @@ func CalculateCacheDir(cacheDir, instanceFQDN string) string {
|
||||||
|
|
||||||
cacheRoot, err := os.UserCacheDir()
|
cacheRoot, err := os.UserCacheDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cacheRoot = "."
|
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)
|
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)
|
||||||
|
|
Loading…
Reference in a new issue