feat: add configuration support to enbas
SUMMARY This commit adds configuration support to enbas. The configuration is stored as a JSON file in the user specified configuration directory. When using enbas for the first time, the user will first need to execute the new init command in order to generate the configuration. Once this has been generated the user can edit the settings to personalise their experience, login to their account and use enbas as normal. For now the configurable settings included in the configuration are as follows: - The path to the credentials file (by default this is set to a file in the same directory as the configuration file). - The path to the cache directory. - The character limit used for line wrapping. - The programs used for integrations such as paging, media viewing, opening URLs, etc. CHANGES - added the new config type. - added the new init executor for generating a new configuration file. - removed the following top level flags in favour of the new configration support. - cache-dir - pager - image-viewer - video-player - max-terminal-width - added a new error type for use when an unknown media attachment ID is specified. - updated the usage function for the executors to support a case where a flagsets has no flags. - update .golangci.yaml to disable some linters
This commit is contained in:
parent
63f0526f39
commit
42251f6df8
30 changed files with 425 additions and 220 deletions
|
@ -31,5 +31,8 @@ linters-settings:
|
|||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
#- json
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- gomnd
|
||||
- tagliatelle
|
||||
fast: false
|
||||
|
|
|
@ -10,15 +10,16 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
var (
|
||||
binaryVersion string
|
||||
buildTime string
|
||||
goVersion string
|
||||
gitCommit string
|
||||
binaryVersion string //nolint:gochecknoglobals
|
||||
buildTime string //nolint:gochecknoglobals
|
||||
goVersion string //nolint:gochecknoglobals
|
||||
gitCommit string //nolint:gochecknoglobals
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -30,21 +31,10 @@ func main() {
|
|||
func run() error {
|
||||
var (
|
||||
configDir string
|
||||
cacheDir string
|
||||
pager string
|
||||
imageViewer string
|
||||
videoPlayer string
|
||||
maxTerminalWidth int
|
||||
noColor *bool
|
||||
)
|
||||
|
||||
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 {
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
|
@ -67,7 +57,8 @@ func run() error {
|
|||
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 {
|
||||
noColor = new(bool)
|
||||
if os.Getenv("NO_COLOR") != "" {
|
||||
|
@ -80,110 +71,132 @@ func run() error {
|
|||
command := flag.Arg(0)
|
||||
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{
|
||||
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandAccept,
|
||||
executor.CommandSummaryLookup(executor.CommandAccept),
|
||||
),
|
||||
executor.CommandAdd: executor.NewAddExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandAdd,
|
||||
executor.CommandSummaryLookup(executor.CommandAdd),
|
||||
),
|
||||
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandBlock,
|
||||
executor.CommandSummaryLookup(executor.CommandBlock),
|
||||
),
|
||||
executor.CommandCreate: executor.NewCreateExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandCreate,
|
||||
executor.CommandSummaryLookup(executor.CommandCreate),
|
||||
),
|
||||
executor.CommandDelete: executor.NewDeleteExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandDelete,
|
||||
executor.CommandSummaryLookup(executor.CommandDelete),
|
||||
),
|
||||
executor.CommandEdit: executor.NewEditExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandEdit,
|
||||
executor.CommandSummaryLookup(executor.CommandEdit),
|
||||
),
|
||||
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandFollow,
|
||||
executor.CommandSummaryLookup(executor.CommandFollow),
|
||||
),
|
||||
executor.CommandLogin: executor.NewLoginExecutor(
|
||||
printer,
|
||||
executor.CommandInit: executor.NewInitExecutor(
|
||||
enbasPrinter,
|
||||
configDir,
|
||||
executor.CommandInit,
|
||||
executor.CommandSummaryLookup(executor.CommandInit),
|
||||
),
|
||||
executor.CommandLogin: executor.NewLoginExecutor(
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandLogin,
|
||||
executor.CommandSummaryLookup(executor.CommandLogin),
|
||||
),
|
||||
executor.CommandMute: executor.NewMuteOrUnmuteExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandMute,
|
||||
executor.CommandSummaryLookup(executor.CommandMute),
|
||||
),
|
||||
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandReject,
|
||||
executor.CommandSummaryLookup(executor.CommandReject),
|
||||
),
|
||||
executor.CommandRemove: executor.NewRemoveExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandRemove,
|
||||
executor.CommandSummaryLookup(executor.CommandRemove),
|
||||
),
|
||||
executor.CommandSwitch: executor.NewSwitchExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandSwitch,
|
||||
executor.CommandSummaryLookup(executor.CommandSwitch),
|
||||
),
|
||||
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandUnfollow,
|
||||
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
||||
),
|
||||
executor.CommandUnmute: executor.NewMuteOrUnmuteExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandUnmute,
|
||||
executor.CommandSummaryLookup(executor.CommandUnmute),
|
||||
),
|
||||
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandUnblock,
|
||||
executor.CommandSummaryLookup(executor.CommandUnblock),
|
||||
),
|
||||
executor.CommandShow: executor.NewShowExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
cacheDir,
|
||||
imageViewer,
|
||||
videoPlayer,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandShow,
|
||||
executor.CommandSummaryLookup(executor.CommandShow),
|
||||
),
|
||||
executor.CommandVersion: executor.NewVersionExecutor(
|
||||
printer,
|
||||
enbasPrinter,
|
||||
executor.CommandVersion,
|
||||
executor.CommandSummaryLookup(executor.CommandVersion),
|
||||
binaryVersion,
|
||||
|
@ -192,8 +205,8 @@ func run() error {
|
|||
gitCommit,
|
||||
),
|
||||
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
||||
printer,
|
||||
configDir,
|
||||
enbasPrinter,
|
||||
enbasConfig,
|
||||
executor.CommandWhoami,
|
||||
executor.CommandSummaryLookup(executor.CommandWhoami),
|
||||
),
|
||||
|
@ -201,16 +214,16 @@ func run() error {
|
|||
|
||||
exe, ok := executorMap[command]
|
||||
if !ok {
|
||||
err := executor.UnknownCommandError{Command: command}
|
||||
err = executor.UnknownCommandError{Command: command}
|
||||
|
||||
printer.PrintFailure(err.Error() + ".")
|
||||
enbasPrinter.PrintFailure(err.Error() + ".")
|
||||
flag.Usage()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := executor.Execute(exe, args); err != nil {
|
||||
printer.PrintFailure("(" + command + ") " + err.Error() + ".")
|
||||
if err = executor.Execute(exe, args); err != nil {
|
||||
enbasPrinter.PrintFailure("(" + command + ") " + err.Error() + ".")
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ type Client struct {
|
|||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func NewClientFromConfig(configDir string) (*Client, error) {
|
||||
config, err := config.NewCredentialsConfigFromFile(configDir)
|
||||
func NewClientFromFile(path string) (*Client, error) {
|
||||
config, err := config.NewCredentialsConfigFromFile(path)
|
||||
if err != nil {
|
||||
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 {
|
||||
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(
|
||||
format,
|
||||
|
|
|
@ -24,7 +24,7 @@ type registerRequest struct {
|
|||
func (g *Client) Register() error {
|
||||
params := registerRequest{
|
||||
ClientName: internal.ApplicationName,
|
||||
RedirectUris: internal.RedirectUri,
|
||||
RedirectUris: internal.RedirectURI,
|
||||
Scopes: "read write",
|
||||
Website: internal.ApplicationWebsite,
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
var errEmptyAccessToken = errors.New("received an empty access token")
|
||||
|
||||
type tokenRequest struct {
|
||||
RedirectUri string `json:"redirect_uri"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
GrantType string `json:"grant_type"`
|
||||
|
@ -33,7 +33,7 @@ type tokenResponse struct {
|
|||
|
||||
func (g *Client) UpdateToken(code string) error {
|
||||
params := tokenRequest{
|
||||
RedirectUri: internal.RedirectUri,
|
||||
RedirectURI: internal.RedirectURI,
|
||||
ClientID: g.Authentication.ClientID,
|
||||
ClientSecret: g.Authentication.ClientSecret,
|
||||
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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
const (
|
||||
credentialsFileName = "credentials.json"
|
||||
defaultCredentialsFileName = "credentials.json"
|
||||
)
|
||||
|
||||
type CredentialsConfig struct {
|
||||
|
@ -42,35 +41,29 @@ func (e CredentialsNotFoundError) Error() string {
|
|||
// 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
|
||||
// is not present, it will be created.
|
||||
func SaveCredentials(configDir, username string, credentials Credentials) (string, error) {
|
||||
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(configDir)); err != nil {
|
||||
func SaveCredentials(filePath, username string, credentials Credentials) (string, error) {
|
||||
directory := filepath.Dir(filePath)
|
||||
|
||||
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(directory)); err != nil {
|
||||
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
} else {
|
||||
authConfig, err = NewCredentialsConfigFromFile(configDir)
|
||||
authConfig, err = NewCredentialsConfigFromFile(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
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://")
|
||||
}
|
||||
instance := utilities.GetFQDN(credentials.Instance)
|
||||
|
||||
authenticationName := username + "@" + instance
|
||||
|
||||
|
@ -78,15 +71,15 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
|
|||
|
||||
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 authenticationName, nil
|
||||
}
|
||||
|
||||
func UpdateCurrentAccount(account string, configDir string) error {
|
||||
credentialsConfig, err := NewCredentialsConfigFromFile(configDir)
|
||||
func UpdateCurrentAccount(account string, filePath string) error {
|
||||
credentialsConfig, err := NewCredentialsConfigFromFile(filePath)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
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 nil
|
||||
}
|
||||
|
||||
func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
|
||||
path := credentialsConfigFile(configDir)
|
||||
|
||||
file, err := os.Open(path)
|
||||
// NewCredentialsConfigFromFile creates a new CredentialsConfig value from reading
|
||||
// the credentials file.
|
||||
func NewCredentialsConfigFromFile(filePath string) (CredentialsConfig, error) {
|
||||
file, err := os.Open(filePath)
|
||||
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()
|
||||
|
||||
|
@ -122,14 +115,11 @@ func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
|
|||
return authConfig, nil
|
||||
}
|
||||
|
||||
func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) error {
|
||||
path := credentialsConfigFile(configDir)
|
||||
|
||||
file, err := os.Create(path)
|
||||
func saveCredentialsConfigFile(authConfig CredentialsConfig, filePath string) error {
|
||||
file, err := os.Create(filePath)
|
||||
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()
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
|
@ -142,6 +132,6 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func credentialsConfigFile(configDir string) string {
|
||||
return filepath.Join(utilities.CalculateConfigDir(configDir), credentialsFileName)
|
||||
func defaultCredentialsConfigFile(configDir string) string {
|
||||
return filepath.Join(utilities.CalculateConfigDir(configDir), defaultCredentialsFileName)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,18 +17,18 @@ type AcceptOrRejectExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
accountName 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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: enbasPrinter,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
command: name,
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: a.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountName, a.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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"
|
||||
)
|
||||
|
||||
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 (
|
||||
accountID string
|
||||
err error
|
||||
|
@ -20,7 +20,7 @@ func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configD
|
|||
|
||||
switch {
|
||||
case myAccount:
|
||||
accountID, err = getMyAccountID(gtsClient, configDir)
|
||||
accountID, err = getMyAccountID(gtsClient, path)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func getMyAccountID(gtsClient *client.Client, configDir string) (string, error) {
|
||||
account, err := getMyAccount(gtsClient, configDir)
|
||||
func getMyAccountID(gtsClient *client.Client, path string) (string, error) {
|
||||
account, err := getMyAccount(gtsClient, path)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, error) {
|
||||
authConfig, err := config.NewCredentialsConfigFromFile(configDir)
|
||||
func getMyAccount(gtsClient *client.Client, path string) (model.Account, error) {
|
||||
authConfig, err := config.NewCredentialsConfigFromFile(path)
|
||||
if err != nil {
|
||||
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration: %w", err)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -17,7 +18,7 @@ type AddExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
toResourceType string
|
||||
listID string
|
||||
|
@ -28,14 +29,14 @@ type AddExecutor struct {
|
|||
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)
|
||||
|
||||
addExe := AddExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
accountNames: MultiStringFlagValue(emptyArr),
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,7 @@ func (a *AddExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: a.toResourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(a.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,18 +17,18 @@ type BlockOrUnblockExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
accountName 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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
command: name,
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: b.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(b.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(b.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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}
|
||||
}
|
||||
|
||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ const (
|
|||
CommandDelete string = "delete"
|
||||
CommandEdit string = "edit"
|
||||
CommandFollow string = "follow"
|
||||
CommandInit string = "init"
|
||||
CommandLogin string = "login"
|
||||
CommandMute string = "mute"
|
||||
CommandReject string = "reject"
|
||||
|
@ -31,6 +32,7 @@ const (
|
|||
commandDeleteSummary string = "Delete a specific resource"
|
||||
commandEditSummary string = "Edit a specific resource"
|
||||
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"
|
||||
commandMuteSummary string = "Mute a resource (e.g. an account)"
|
||||
commandRejectSummary string = "Reject a request (e.g. a follow request)"
|
||||
|
@ -53,6 +55,7 @@ func CommandSummaryMap() map[string]string {
|
|||
CommandDelete: commandDeleteSummary,
|
||||
CommandEdit: commandEditSummary,
|
||||
CommandFollow: commandFollowSummary,
|
||||
CommandInit: commandInitSummary,
|
||||
CommandLogin: commandLoginSummary,
|
||||
CommandMute: commandMuteSummary,
|
||||
CommandReject: commandRejectSummary,
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"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/printer"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
|
@ -19,6 +20,7 @@ type CreateExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
config *config.Config
|
||||
addPoll bool
|
||||
boostable bool
|
||||
federated bool
|
||||
|
@ -27,7 +29,6 @@ type CreateExecutor struct {
|
|||
pollHidesVoteCounts bool
|
||||
replyable bool
|
||||
sensitive *bool
|
||||
configDir string
|
||||
content string
|
||||
contentType string
|
||||
fromFile string
|
||||
|
@ -41,12 +42,12 @@ type CreateExecutor struct {
|
|||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(c.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(c.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,17 +17,17 @@ type DeleteExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType 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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(d.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(d.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"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/printer"
|
||||
)
|
||||
|
@ -17,19 +18,19 @@ type EditExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
listID string
|
||||
listTitle 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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(e.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(e.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||
}
|
||||
|
|
|
@ -102,3 +102,11 @@ type NotFollowingError struct {
|
|||
func (e NotFollowingError) Error() string {
|
||||
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"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ type FollowOrUnfollowExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
accountName string
|
||||
showReposts bool
|
||||
|
@ -24,12 +25,12 @@ type FollowOrUnfollowExecutor struct {
|
|||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
action: name,
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: f.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(f.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(f.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, f.accountName, f.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
|
@ -19,16 +19,16 @@ type LoginExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
instance: "",
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func (c *LoginExecutor) Execute() error {
|
|||
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 {
|
||||
return fmt.Errorf("unable to save the authentication details: %w", err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,20 +17,20 @@ type MuteOrUnmuteExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
config *config.Config
|
||||
accountName string
|
||||
configDir string
|
||||
command string
|
||||
resourceType string
|
||||
muteDuration TimeDurationFlagValue
|
||||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
command: name,
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (m *MuteOrUnmuteExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: m.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(m.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(m.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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}
|
||||
}
|
||||
|
||||
accountID, err := getAccountID(gtsClient, false, m.accountName, m.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, m.accountName, m.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ type RemoveExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
config *config.Config
|
||||
resourceType string
|
||||
fromResourceType string
|
||||
listID string
|
||||
|
@ -24,14 +25,14 @@ type RemoveExecutor struct {
|
|||
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)
|
||||
|
||||
removeExe := RemoveExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
accountNames: MultiStringFlagValue(emptyArr),
|
||||
}
|
||||
|
||||
|
@ -63,7 +64,7 @@ func (r *RemoveExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: r.fromResourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(r.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(r.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
|
||||
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.configDir)
|
||||
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"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/printer"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
|
@ -20,12 +21,11 @@ type ShowExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
config *config.Config
|
||||
myAccount bool
|
||||
skipAccountRelationship bool
|
||||
showUserPreferences bool
|
||||
showInBrowser bool
|
||||
configDir string
|
||||
cacheRoot string
|
||||
resourceType string
|
||||
accountName string
|
||||
statusID string
|
||||
|
@ -34,21 +34,16 @@ type ShowExecutor struct {
|
|||
tag string
|
||||
pollID string
|
||||
fromResourceType string
|
||||
imageViewer string
|
||||
videoPlayer string
|
||||
limit int
|
||||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
cacheRoot: cacheRoot,
|
||||
imageViewer: imageViewer,
|
||||
videoPlayer: videoPlayer,
|
||||
config: config,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(s.configDir)
|
||||
gtsClient, err := client.NewClientFromFile(s.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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 {
|
||||
account, err = getMyAccount(gtsClient, s.configDir)
|
||||
account, err = getMyAccount(gtsClient, s.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
||||
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.config.CredentialsFile)
|
||||
if err != nil {
|
||||
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(
|
||||
utilities.CalculateCacheDir(s.cacheRoot, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
||||
utilities.CalculateCacheDir(s.config.CacheDirectory, utilities.GetFQDN(gtsClient.Authentication.Instance)),
|
||||
"media",
|
||||
)
|
||||
|
||||
|
@ -498,7 +493,7 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
|||
for _, attachmentID := range s.attachmentIDs {
|
||||
mediaObj, ok := attachmentsHashMap[attachmentID]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown media attachment: %s", attachmentID)
|
||||
return UnknownMediaAttachmentError{AttachmentID: attachmentID}
|
||||
}
|
||||
|
||||
split := strings.Split(mediaObj.url, "/")
|
||||
|
@ -533,13 +528,13 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,17 @@ import (
|
|||
type SwitchExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
configDir string
|
||||
config *config.Config
|
||||
toResourceType string
|
||||
accountName string
|
||||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
}
|
||||
|
||||
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
||||
|
@ -54,7 +54,7 @@ func (s *SwitchExecutor) switchToAccount() error {
|
|||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ package executor
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -15,27 +15,41 @@ func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
|
|||
return func() {
|
||||
var builder strings.Builder
|
||||
|
||||
fmt.Fprintf(
|
||||
&builder,
|
||||
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
|
||||
name,
|
||||
summary,
|
||||
name,
|
||||
)
|
||||
builder.WriteString("SUMMARY:")
|
||||
builder.WriteString("\n " + name + " - " + summary)
|
||||
builder.WriteString("\n\nUSAGE:")
|
||||
builder.WriteString("\n enbas " + name)
|
||||
|
||||
flagMap := make(map[string]string)
|
||||
|
||||
flagset.VisitAll(func(f *flag.Flag) {
|
||||
fmt.Fprintf(
|
||||
&builder,
|
||||
"\n --%s\n %s",
|
||||
f.Name,
|
||||
f.Usage,
|
||||
)
|
||||
flagMap[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")
|
||||
|
||||
w := flag.CommandLine.Output()
|
||||
|
||||
fmt.Fprint(w, builder.String())
|
||||
_, _ = w.Write([]byte(builder.String()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
type VersionExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
printer *printer.Printer
|
||||
showFullVersion bool
|
||||
binaryVersion string
|
||||
|
@ -21,7 +22,7 @@ type VersionExecutor struct {
|
|||
}
|
||||
|
||||
func NewVersionExecutor(
|
||||
enbasPrinter *printer.Printer,
|
||||
printer *printer.Printer,
|
||||
name,
|
||||
summary,
|
||||
binaryVersion,
|
||||
|
@ -32,7 +33,7 @@ func NewVersionExecutor(
|
|||
command := VersionExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: enbasPrinter,
|
||||
printer: printer,
|
||||
binaryVersion: binaryVersion,
|
||||
buildTime: buildTime,
|
||||
goVersion: goVersion,
|
||||
|
|
|
@ -16,15 +16,15 @@ type WhoAmIExecutor struct {
|
|||
*flag.FlagSet
|
||||
|
||||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
config: config,
|
||||
}
|
||||
|
||||
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 {
|
||||
config, err := config.NewCredentialsConfigFromFile(c.configDir)
|
||||
config, err := config.NewCredentialsConfigFromFile(c.config.CredentialsFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load the credential config: %w", err)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ package internal
|
|||
const (
|
||||
ApplicationName = "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"
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ type Application struct {
|
|||
ClientSecret string `json:"client_secret"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RedirectUri string `json:"redirect_uri"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
VapidKey string `json:"vapid_key"`
|
||||
Website string `json:"website"`
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func CalculateConfigDir(configDir string) string {
|
|||
|
||||
configRoot, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
configRoot = "."
|
||||
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "config")
|
||||
}
|
||||
|
||||
return filepath.Join(configRoot, internal.ApplicationName)
|
||||
|
@ -33,7 +33,7 @@ func CalculateCacheDir(cacheDir, instanceFQDN string) string {
|
|||
|
||||
cacheRoot, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
cacheRoot = "."
|
||||
return filepath.Join(os.Getenv("HOME"), "."+internal.ApplicationName, "cache")
|
||||
}
|
||||
|
||||
return filepath.Join(cacheRoot, internal.ApplicationName, instanceFQDN)
|
||||
|
|
Loading…
Reference in a new issue