fix: add a new internal printer #25
33 changed files with 938 additions and 808 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -22,47 +23,33 @@ var (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := run(); err != nil {
|
if err := run(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "ERROR: %v.\n", err)
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
topLevelFlags := executor.TopLevelFlags{
|
var (
|
||||||
ConfigDir: "",
|
configDir string
|
||||||
NoColor: nil,
|
pager string
|
||||||
Pager: "",
|
maxTerminalWidth int
|
||||||
}
|
noColor *bool
|
||||||
|
|
||||||
flag.StringVar(
|
|
||||||
&topLevelFlags.ConfigDir,
|
|
||||||
"config-dir",
|
|
||||||
"",
|
|
||||||
"Specify your config directory",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.BoolFunc(
|
flag.StringVar(&configDir, "config-dir", "", "Specify your config directory")
|
||||||
"no-color",
|
flag.StringVar(&pager, "pager", "", "Specify your preferred pager to page through long outputs. This is disabled by default.")
|
||||||
"Disable ANSI colour output when displaying text on screen",
|
flag.IntVar(&maxTerminalWidth, "max-terminal-width", 80, "Specify the maximum terminal width when displaying resources 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 {
|
||||||
return fmt.Errorf("unable to parse %q as a boolean: %w", value, err)
|
return fmt.Errorf("unable to parse %q as a boolean: %w", value, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
topLevelFlags.NoColor = new(bool)
|
noColor = new(bool)
|
||||||
*topLevelFlags.NoColor = boolVal
|
*noColor = boolVal
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
})
|
||||||
)
|
|
||||||
|
|
||||||
flag.StringVar(
|
|
||||||
&topLevelFlags.Pager,
|
|
||||||
"pager",
|
|
||||||
"",
|
|
||||||
"Specify your preferred pager to page through long outputs. This is disabled by default.",
|
|
||||||
)
|
|
||||||
|
|
||||||
flag.Usage = usageFunc(executor.CommandSummaryMap())
|
flag.Usage = usageFunc(executor.CommandSummaryMap())
|
||||||
|
|
||||||
|
@ -75,90 +62,107 @@ func run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 topLevelFlags.NoColor == nil {
|
if noColor == nil {
|
||||||
topLevelFlags.NoColor = new(bool)
|
noColor = new(bool)
|
||||||
if os.Getenv("NO_COLOR") != "" {
|
if os.Getenv("NO_COLOR") != "" {
|
||||||
*topLevelFlags.NoColor = true
|
*noColor = true
|
||||||
} else {
|
} else {
|
||||||
*topLevelFlags.NoColor = false
|
*noColor = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
command := flag.Arg(0)
|
command := flag.Arg(0)
|
||||||
args := flag.Args()[1:]
|
args := flag.Args()[1:]
|
||||||
|
|
||||||
|
printer := printer.NewPrinter(*noColor, pager, maxTerminalWidth)
|
||||||
|
|
||||||
executorMap := map[string]executor.Executor{
|
executorMap := map[string]executor.Executor{
|
||||||
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandAccept,
|
executor.CommandAccept,
|
||||||
executor.CommandSummaryLookup(executor.CommandAccept),
|
executor.CommandSummaryLookup(executor.CommandAccept),
|
||||||
),
|
),
|
||||||
executor.CommandAdd: executor.NewAddExecutor(
|
executor.CommandAdd: executor.NewAddExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandAdd,
|
executor.CommandAdd,
|
||||||
executor.CommandSummaryLookup(executor.CommandAdd),
|
executor.CommandSummaryLookup(executor.CommandAdd),
|
||||||
),
|
),
|
||||||
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandBlock,
|
executor.CommandBlock,
|
||||||
executor.CommandSummaryLookup(executor.CommandBlock),
|
executor.CommandSummaryLookup(executor.CommandBlock),
|
||||||
),
|
),
|
||||||
executor.CommandCreate: executor.NewCreateExecutor(
|
executor.CommandCreate: executor.NewCreateExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandCreate,
|
executor.CommandCreate,
|
||||||
executor.CommandSummaryLookup(executor.CommandCreate),
|
executor.CommandSummaryLookup(executor.CommandCreate),
|
||||||
),
|
),
|
||||||
executor.CommandDelete: executor.NewDeleteExecutor(
|
executor.CommandDelete: executor.NewDeleteExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandDelete,
|
executor.CommandDelete,
|
||||||
executor.CommandSummaryLookup(executor.CommandDelete),
|
executor.CommandSummaryLookup(executor.CommandDelete),
|
||||||
),
|
),
|
||||||
executor.CommandEdit: executor.NewEditExecutor(
|
executor.CommandEdit: executor.NewEditExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandEdit,
|
executor.CommandEdit,
|
||||||
executor.CommandSummaryLookup(executor.CommandEdit),
|
executor.CommandSummaryLookup(executor.CommandEdit),
|
||||||
),
|
),
|
||||||
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandFollow,
|
executor.CommandFollow,
|
||||||
executor.CommandSummaryLookup(executor.CommandFollow),
|
executor.CommandSummaryLookup(executor.CommandFollow),
|
||||||
),
|
),
|
||||||
executor.CommandLogin: executor.NewLoginExecutor(
|
executor.CommandLogin: executor.NewLoginExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandLogin,
|
executor.CommandLogin,
|
||||||
executor.CommandSummaryLookup(executor.CommandLogin),
|
executor.CommandSummaryLookup(executor.CommandLogin),
|
||||||
),
|
),
|
||||||
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandReject,
|
executor.CommandReject,
|
||||||
executor.CommandSummaryLookup(executor.CommandReject),
|
executor.CommandSummaryLookup(executor.CommandReject),
|
||||||
),
|
),
|
||||||
executor.CommandRemove: executor.NewRemoveExecutor(
|
executor.CommandRemove: executor.NewRemoveExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandRemove,
|
executor.CommandRemove,
|
||||||
executor.CommandSummaryLookup(executor.CommandRemove),
|
executor.CommandSummaryLookup(executor.CommandRemove),
|
||||||
),
|
),
|
||||||
executor.CommandSwitch: executor.NewSwitchExecutor(
|
executor.CommandSwitch: executor.NewSwitchExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandSwitch,
|
executor.CommandSwitch,
|
||||||
executor.CommandSummaryLookup(executor.CommandSwitch),
|
executor.CommandSummaryLookup(executor.CommandSwitch),
|
||||||
),
|
),
|
||||||
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandUnfollow,
|
executor.CommandUnfollow,
|
||||||
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
||||||
),
|
),
|
||||||
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandUnblock,
|
executor.CommandUnblock,
|
||||||
executor.CommandSummaryLookup(executor.CommandUnblock),
|
executor.CommandSummaryLookup(executor.CommandUnblock),
|
||||||
),
|
),
|
||||||
executor.CommandShow: executor.NewShowExecutor(
|
executor.CommandShow: executor.NewShowExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandShow,
|
executor.CommandShow,
|
||||||
executor.CommandSummaryLookup(executor.CommandShow),
|
executor.CommandSummaryLookup(executor.CommandShow),
|
||||||
),
|
),
|
||||||
executor.CommandVersion: executor.NewVersionExecutor(
|
executor.CommandVersion: executor.NewVersionExecutor(
|
||||||
|
printer,
|
||||||
executor.CommandVersion,
|
executor.CommandVersion,
|
||||||
executor.CommandSummaryLookup(executor.CommandVersion),
|
executor.CommandSummaryLookup(executor.CommandVersion),
|
||||||
binaryVersion,
|
binaryVersion,
|
||||||
|
@ -167,7 +171,8 @@ func run() error {
|
||||||
gitCommit,
|
gitCommit,
|
||||||
),
|
),
|
||||||
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
||||||
topLevelFlags,
|
printer,
|
||||||
|
configDir,
|
||||||
executor.CommandWhoami,
|
executor.CommandWhoami,
|
||||||
executor.CommandSummaryLookup(executor.CommandWhoami),
|
executor.CommandSummaryLookup(executor.CommandWhoami),
|
||||||
),
|
),
|
||||||
|
@ -175,13 +180,18 @@ func run() error {
|
||||||
|
|
||||||
exe, ok := executorMap[command]
|
exe, ok := executorMap[command]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
err := executor.UnknownCommandError{Command: command}
|
||||||
|
|
||||||
|
printer.PrintFailure(err.Error() + ".")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
|
|
||||||
return executor.UnknownCommandError{Command: command}
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := executor.Execute(exe, args); err != nil {
|
if err := executor.Execute(exe, args); err != nil {
|
||||||
return fmt.Errorf("(%s) %w", command, err)
|
printer.PrintFailure("(" + command + ") " + err.Error() + ".")
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -39,21 +39,27 @@ func (g *Client) GetAccount(accountURI string) (model.Account, error) {
|
||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Client) GetAccountRelationship(accountID string) (model.AccountRelationship, error) {
|
func (g *Client) GetAccountRelationship(accountID string) (*model.AccountRelationship, error) {
|
||||||
path := "/api/v1/accounts/relationships?id=" + accountID
|
path := "/api/v1/accounts/relationships?id=" + accountID
|
||||||
url := g.Authentication.Instance + path
|
url := g.Authentication.Instance + path
|
||||||
|
|
||||||
var relationships []model.AccountRelationship
|
var relationships []model.AccountRelationship
|
||||||
|
|
||||||
if err := g.sendRequest(http.MethodGet, url, nil, &relationships); err != nil {
|
if err := g.sendRequest(http.MethodGet, url, nil, &relationships); err != nil {
|
||||||
return model.AccountRelationship{}, fmt.Errorf("received an error after sending the request to get the account relationship: %w", err)
|
return nil, fmt.Errorf(
|
||||||
|
"received an error after sending the request to get the account relationship: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(relationships) != 1 {
|
if len(relationships) != 1 {
|
||||||
return model.AccountRelationship{}, fmt.Errorf("unexpected number of account relationships returned: want 1, got %d", len(relationships))
|
return nil, fmt.Errorf(
|
||||||
|
"unexpected number of account relationships returned: want 1, got %d",
|
||||||
|
len(relationships),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return relationships[0], nil
|
return &relationships[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FollowAccountForm struct {
|
type FollowAccountForm struct {
|
||||||
|
|
|
@ -17,7 +17,7 @@ const (
|
||||||
listPath string = "/api/v1/lists"
|
listPath string = "/api/v1/lists"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *Client) GetAllLists() (model.Lists, error) {
|
func (g *Client) GetAllLists() ([]model.List, error) {
|
||||||
url := g.Authentication.Instance + listPath
|
url := g.Authentication.Instance + listPath
|
||||||
|
|
||||||
var lists []model.List
|
var lists []model.List
|
||||||
|
|
|
@ -11,14 +11,14 @@ import (
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *Client) GetUserPreferences() (model.Preferences, error) {
|
func (g *Client) GetUserPreferences() (*model.Preferences, error) {
|
||||||
url := g.Authentication.Instance + "/api/v1/preferences"
|
url := g.Authentication.Instance + "/api/v1/preferences"
|
||||||
|
|
||||||
var preferences model.Preferences
|
var preferences model.Preferences
|
||||||
|
|
||||||
if err := g.sendRequest(http.MethodGet, url, nil, &preferences); err != nil {
|
if err := g.sendRequest(http.MethodGet, url, nil, &preferences); err != nil {
|
||||||
return model.Preferences{}, fmt.Errorf("received an error after sending the request to get the user preferences: %w", err)
|
return nil, fmt.Errorf("received an error after sending the request to get the user preferences: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return preferences, nil
|
return &preferences, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,22 +9,25 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AcceptOrRejectExecutor struct {
|
type AcceptOrRejectExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
command string
|
command string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAcceptOrRejectExecutor(tlf TopLevelFlags, name, summary string) *AcceptOrRejectExecutor {
|
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, configDir, name, summary string) *AcceptOrRejectExecutor {
|
||||||
acceptExe := AcceptOrRejectExecutor{
|
acceptExe := AcceptOrRejectExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
topLevelFlags: tlf,
|
printer: enbasPrinter,
|
||||||
|
configDir: configDir,
|
||||||
command: name,
|
command: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +49,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: a.resourceType}
|
return UnsupportedTypeError{resourceType: a.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ func (a *AcceptOrRejectExecutor) acceptFollowRequest(gtsClient *client.Client, a
|
||||||
return fmt.Errorf("unable to accept the follow request: %w", err)
|
return fmt.Errorf("unable to accept the follow request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully accepted the follow request.")
|
a.printer.PrintSuccess("Successfully accepted the follow request.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,7 @@ func (a *AcceptOrRejectExecutor) rejectFollowRequest(gtsClient *client.Client, a
|
||||||
return fmt.Errorf("unable to reject the follow request: %w", err)
|
return fmt.Errorf("unable to reject the follow request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully rejected the follow request.")
|
a.printer.PrintSuccess("Successfully rejected the follow request.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddExecutor struct {
|
type AddExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
toResourceType string
|
toResourceType string
|
||||||
listID string
|
listID string
|
||||||
|
@ -26,13 +28,15 @@ type AddExecutor struct {
|
||||||
content string
|
content string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAddExecutor(tlf TopLevelFlags, name, summary string) *AddExecutor {
|
func NewAddExecutor(printer *printer.Printer, configDir, 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,
|
||||||
|
configDir: configDir,
|
||||||
accountNames: MultiStringFlagValue(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
topLevelFlags: tlf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addExe.StringVar(&addExe.resourceType, flagType, "", "Specify the resource type to add (e.g. account, note)")
|
addExe.StringVar(&addExe.resourceType, flagType, "", "Specify the resource type to add (e.g. account, note)")
|
||||||
|
@ -67,7 +71,7 @@ func (a *AddExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: a.toResourceType}
|
return UnsupportedTypeError{resourceType: a.toResourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -124,7 +128,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add the accounts to the list: %w", err)
|
return fmt.Errorf("unable to add the accounts to the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully added the account(s) to the list.")
|
a.printer.PrintSuccess("Successfully added the account(s) to the list.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -150,7 +154,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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -166,7 +170,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add the private note to the account: %w", err)
|
return fmt.Errorf("unable to add the private note to the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully added the private note to the account.")
|
a.printer.PrintSuccess("Successfully added the private note to the account.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -196,7 +200,7 @@ func (a *AddExecutor) addStatusToBookmarks(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add the status to your bookmarks: %w", err)
|
return fmt.Errorf("unable to add the status to your bookmarks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully added the status to your bookmarks.")
|
a.printer.PrintSuccess("Successfully added the status to your bookmarks.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -228,7 +232,7 @@ func (a *AddExecutor) addStarToStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add the %s to the status: %w", a.resourceType, err)
|
return fmt.Errorf("unable to add the %s to the status: %w", a.resourceType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Successfully added a %s to the status.\n", a.resourceType)
|
a.printer.PrintSuccess("Successfully added a " + a.resourceType + " to the status.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -238,7 +242,7 @@ func (a *AddExecutor) addBoostToStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add the boost to the status: %w", err)
|
return fmt.Errorf("unable to add the boost to the status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully added the boost to the status.")
|
a.printer.PrintSuccess("Successfully added the boost to the status.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -285,7 +289,7 @@ func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to add your vote(s) to the poll: %w", err)
|
return fmt.Errorf("unable to add your vote(s) to the poll: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully added your vote(s) to the poll.")
|
a.printer.PrintSuccess("Successfully added your vote(s) to the poll.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,22 +9,25 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockOrUnblockExecutor struct {
|
type BlockOrUnblockExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
command string
|
command string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockOrUnblockExecutor(tlf TopLevelFlags, name, summary string) *BlockOrUnblockExecutor {
|
func NewBlockOrUnblockExecutor(printer *printer.Printer, configDir, name, summary string) *BlockOrUnblockExecutor {
|
||||||
blockExe := BlockOrUnblockExecutor{
|
blockExe := BlockOrUnblockExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
topLevelFlags: tlf,
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
command: name,
|
command: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +49,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: b.resourceType}
|
return UnsupportedTypeError{resourceType: b.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(b.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(b.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlockOrUnblockExecutor) blockOrUnblockAccount(gtsClient *client.Client) error {
|
func (b *BlockOrUnblockExecutor) blockOrUnblockAccount(gtsClient *client.Client) error {
|
||||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ func (b *BlockOrUnblockExecutor) blockAccount(gtsClient *client.Client, accountI
|
||||||
return fmt.Errorf("unable to block the account: %w", err)
|
return fmt.Errorf("unable to block the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully blocked the account.")
|
b.printer.PrintSuccess("Successfully blocked the account.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,7 @@ func (b *BlockOrUnblockExecutor) unblockAccount(gtsClient *client.Client, accoun
|
||||||
return fmt.Errorf("unable to unblock the account: %w", err)
|
return fmt.Errorf("unable to unblock the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully unblocked the account.")
|
b.printer.PrintSuccess("Successfully unblocked the account.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,14 @@ import (
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
"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/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateExecutor struct {
|
type CreateExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
addPoll bool
|
addPoll bool
|
||||||
boostable bool
|
boostable bool
|
||||||
federated bool
|
federated bool
|
||||||
|
@ -26,6 +27,7 @@ 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
|
||||||
|
@ -39,11 +41,12 @@ type CreateExecutor struct {
|
||||||
pollOptions MultiStringFlagValue
|
pollOptions MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor {
|
func NewCreateExecutor(printer *printer.Printer, configDir, name, summary string) *CreateExecutor {
|
||||||
createExe := CreateExecutor{
|
createExe := CreateExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
topLevelFlags: tlf,
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
||||||
|
@ -87,7 +90,7 @@ func (c *CreateExecutor) Execute() error {
|
||||||
return FlagNotSetError{flagText: flagType}
|
return FlagNotSetError{flagText: flagType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(c.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -125,8 +128,8 @@ func (c *CreateExecutor) createList(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to create the list: %w", err)
|
return fmt.Errorf("unable to create the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully created the following list:")
|
c.printer.PrintSuccess("Successfully created the following list:")
|
||||||
utilities.Display(list, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
|
c.printer.PrintList(list)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -222,8 +225,8 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to create the status: %w", err)
|
return fmt.Errorf("unable to create the status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully created the following status:")
|
c.printer.PrintSuccess("Successfully created the following status:")
|
||||||
utilities.Display(status, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
|
c.printer.PrintStatus(status)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,24 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeleteExecutor struct {
|
type DeleteExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
listID string
|
listID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDeleteExecutor(tlf TopLevelFlags, name, summary string) *DeleteExecutor {
|
func NewDeleteExecutor(printer *printer.Printer, configDir, name, summary string) *DeleteExecutor {
|
||||||
deleteExe := DeleteExecutor{
|
deleteExe := DeleteExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
|
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
|
||||||
|
@ -47,7 +51,7 @@ func (d *DeleteExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: d.resourceType}
|
return UnsupportedTypeError{resourceType: d.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(d.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(d.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -64,7 +68,7 @@ func (d *DeleteExecutor) deleteList(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to delete the list: %w", err)
|
return fmt.Errorf("unable to delete the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("The list was successfully deleted.")
|
d.printer.PrintSuccess("The list was successfully deleted.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,26 @@ import (
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EditExecutor struct {
|
type EditExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
listID string
|
listID string
|
||||||
listTitle string
|
listTitle string
|
||||||
listRepliesPolicy string
|
listRepliesPolicy string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditExecutor(tlf TopLevelFlags, name, summary string) *EditExecutor {
|
func NewEditExecutor(printer *printer.Printer, configDir, name, summary string) *EditExecutor {
|
||||||
editExe := EditExecutor{
|
editExe := EditExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
|
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
|
||||||
|
@ -53,7 +56,7 @@ func (e *EditExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: e.resourceType}
|
return UnsupportedTypeError{resourceType: e.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(e.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(e.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -89,8 +92,8 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to update the list: %w", err)
|
return fmt.Errorf("unable to update the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully updated the list.")
|
e.printer.PrintSuccess("Successfully updated the list.")
|
||||||
utilities.Display(updatedList, *e.topLevelFlags.NoColor, e.topLevelFlags.Pager)
|
e.printer.PrintList(updatedList)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,6 @@ const (
|
||||||
flagVisibility = "visibility"
|
flagVisibility = "visibility"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TopLevelFlags struct {
|
|
||||||
ConfigDir string
|
|
||||||
NoColor *bool
|
|
||||||
Pager string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiStringFlagValue []string
|
type MultiStringFlagValue []string
|
||||||
|
|
||||||
func (v *MultiStringFlagValue) String() string {
|
func (v *MultiStringFlagValue) String() string {
|
||||||
|
|
|
@ -9,12 +9,14 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FollowOrUnfollowExecutor struct {
|
type FollowOrUnfollowExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
showReposts bool
|
showReposts bool
|
||||||
|
@ -22,11 +24,12 @@ type FollowOrUnfollowExecutor struct {
|
||||||
action string
|
action string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFollowOrUnfollowExecutor(tlf TopLevelFlags, name, summary string) *FollowOrUnfollowExecutor {
|
func NewFollowOrUnfollowExecutor(printer *printer.Printer, configDir, name, summary string) *FollowOrUnfollowExecutor {
|
||||||
command := FollowOrUnfollowExecutor{
|
command := FollowOrUnfollowExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
topLevelFlags: tlf,
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
action: name,
|
action: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: f.resourceType}
|
return UnsupportedTypeError{resourceType: f.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(f.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(f.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,7 @@ func (f *FollowOrUnfollowExecutor) followAccount(gtsClient *client.Client, accou
|
||||||
return fmt.Errorf("unable to follow the account: %w", err)
|
return fmt.Errorf("unable to follow the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("The follow request was sent successfully.")
|
f.printer.PrintSuccess("Successfully sent the follow request.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -95,7 +98,7 @@ func (f *FollowOrUnfollowExecutor) unfollowAccount(gtsClient *client.Client, acc
|
||||||
return fmt.Errorf("unable to unfollow the account: %w", err)
|
return fmt.Errorf("unable to unfollow the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully unfollowed the account.")
|
f.printer.PrintSuccess("Successfully unfollowed the account.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,24 @@ import (
|
||||||
|
|
||||||
"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/config"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginExecutor struct {
|
type LoginExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
instance string
|
instance string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoginExecutor(tlf TopLevelFlags, name, summary string) *LoginExecutor {
|
func NewLoginExecutor(printer *printer.Printer, configDir, name, summary string) *LoginExecutor {
|
||||||
command := LoginExecutor{
|
command := LoginExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
instance: "",
|
instance: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,21 +70,17 @@ func (c *LoginExecutor) Execute() error {
|
||||||
|
|
||||||
utilities.OpenLink(consentPageURL)
|
utilities.OpenLink(consentPageURL)
|
||||||
|
|
||||||
consentMessageFormat := `
|
var builder strings.Builder
|
||||||
You'll need to sign into your GoToSocial's consent page in order to generate the out-of-band token to continue with
|
|
||||||
the application's login process. Your browser may have opened the link to the consent page already. If not, please
|
|
||||||
copy and paste the link below to your browser:
|
|
||||||
|
|
||||||
%s
|
builder.WriteString("\nYou'll need to sign into your GoToSocial's consent page in order to generate the out-of-band token to continue with the application's login process.")
|
||||||
|
builder.WriteString("\nYour browser may have opened the link to the consent page already. If not, please copy and paste the link below to your browser:")
|
||||||
|
builder.WriteString("\n\n" + consentPageURL)
|
||||||
|
builder.WriteString("\n\n" + "Once you have the code please copy and paste it below.")
|
||||||
|
builder.WriteString("\n" + "Out-of-band token: ")
|
||||||
|
|
||||||
Once you have the code please copy and paste it below.
|
c.printer.PrintInfo(builder.String())
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
fmt.Printf(consentMessageFormat, consentPageURL)
|
|
||||||
|
|
||||||
var code string
|
var code string
|
||||||
fmt.Print("Out-of-band token: ")
|
|
||||||
|
|
||||||
if _, err := fmt.Scanln(&code); err != nil {
|
if _, err := fmt.Scanln(&code); err != nil {
|
||||||
return fmt.Errorf("failed to read access code: %w", err)
|
return fmt.Errorf("failed to read access code: %w", err)
|
||||||
|
@ -95,12 +95,12 @@ Once you have the code please copy and paste it below.
|
||||||
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.topLevelFlags.ConfigDir, account.Username, gtsClient.Authentication)
|
loginName, err := config.SaveCredentials(c.configDir, 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Successfully logged into %s\n", loginName)
|
c.printer.PrintSuccess("Successfully logged into " + loginName + ".")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,14 @@ 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/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RemoveExecutor struct {
|
type RemoveExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
fromResourceType string
|
fromResourceType string
|
||||||
listID string
|
listID string
|
||||||
|
@ -22,13 +24,15 @@ type RemoveExecutor struct {
|
||||||
accountNames MultiStringFlagValue
|
accountNames MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor {
|
func NewRemoveExecutor(printer *printer.Printer, configDir, 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,
|
||||||
|
configDir: configDir,
|
||||||
accountNames: MultiStringFlagValue(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
topLevelFlags: tlf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeExe.StringVar(&removeExe.resourceType, flagType, "", "Specify the resource type to remove (e.g. account, note)")
|
removeExe.StringVar(&removeExe.resourceType, flagType, "", "Specify the resource type to remove (e.g. account, note)")
|
||||||
|
@ -59,7 +63,7 @@ func (r *RemoveExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: r.fromResourceType}
|
return UnsupportedTypeError{resourceType: r.fromResourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(r.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(r.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +111,7 @@ func (r *RemoveExecutor) removeAccountsFromList(gtsClient *client.Client) error
|
||||||
return fmt.Errorf("unable to remove the accounts from the list: %w", err)
|
return fmt.Errorf("unable to remove the accounts from the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully removed the account(s) from the list.")
|
r.printer.PrintSuccess("Successfully removed the account(s) from the list.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -133,7 +137,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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -142,7 +146,7 @@ func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to remove the private note from the account: %w", err)
|
return fmt.Errorf("unable to remove the private note from the account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully removed the private note from the account.")
|
r.printer.PrintSuccess("Successfully removed the private note from the account.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -172,7 +176,7 @@ func (r *RemoveExecutor) removeStatusFromBookmarks(gtsClient *client.Client) err
|
||||||
return fmt.Errorf("unable to remove the status from your bookmarks: %w", err)
|
return fmt.Errorf("unable to remove the status from your bookmarks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully removed the status from your bookmarks.")
|
r.printer.PrintSuccess("Successfully removed the status from your bookmarks.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -204,7 +208,7 @@ func (r *RemoveExecutor) removeStarFromStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to remove the %s from the status: %w", r.resourceType, err)
|
return fmt.Errorf("unable to remove the %s from the status: %w", r.resourceType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Successfully removed the %s from the status.\n", r.resourceType)
|
r.printer.PrintSuccess("Successfully removed the " + r.resourceType + " from the status.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -214,7 +218,7 @@ func (r *RemoveExecutor) removeBoostFromStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to remove the boost from the status: %w", err)
|
return fmt.Errorf("unable to remove the boost from the status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Successfully removed the boost from the status.")
|
r.printer.PrintSuccess("Successfully removed the boost from the status.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,19 @@ import (
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
"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/utilities"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ShowExecutor struct {
|
type ShowExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
topLevelFlags TopLevelFlags
|
|
||||||
|
printer *printer.Printer
|
||||||
myAccount bool
|
myAccount bool
|
||||||
skipAccountRelationship bool
|
skipAccountRelationship bool
|
||||||
showUserPreferences bool
|
showUserPreferences bool
|
||||||
showInBrowser bool
|
showInBrowser bool
|
||||||
|
configDir string
|
||||||
resourceType string
|
resourceType string
|
||||||
accountName string
|
accountName string
|
||||||
statusID string
|
statusID string
|
||||||
|
@ -30,10 +33,12 @@ type ShowExecutor struct {
|
||||||
limit int
|
limit int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShowExecutor(tlf TopLevelFlags, name, summary string) *ShowExecutor {
|
func NewShowExecutor(printer *printer.Printer, configDir, name, summary string) *ShowExecutor {
|
||||||
showExe := ShowExecutor{
|
showExe := ShowExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
||||||
|
@ -80,7 +85,7 @@ func (s *ShowExecutor) Execute() error {
|
||||||
return UnsupportedTypeError{resourceType: s.resourceType}
|
return UnsupportedTypeError{resourceType: s.resourceType}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient, err := client.NewClientFromConfig(s.topLevelFlags.ConfigDir)
|
gtsClient, err := client.NewClientFromConfig(s.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ func (s *ShowExecutor) showInstance(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to retrieve the instance details: %w", err)
|
return fmt.Errorf("unable to retrieve the instance details: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(instance, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintInstance(instance)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -106,7 +111,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
||||||
)
|
)
|
||||||
|
|
||||||
if s.myAccount {
|
if s.myAccount {
|
||||||
account, err = getMyAccount(gtsClient, s.topLevelFlags.ConfigDir)
|
account, err = getMyAccount(gtsClient, s.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -127,26 +132,27 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(account, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
var (
|
||||||
|
relationship *model.AccountRelationship = nil
|
||||||
|
preferences *model.Preferences = nil
|
||||||
|
)
|
||||||
|
|
||||||
if !s.myAccount && !s.skipAccountRelationship {
|
if !s.myAccount && !s.skipAccountRelationship {
|
||||||
relationship, err := gtsClient.GetAccountRelationship(account.ID)
|
relationship, err = gtsClient.GetAccountRelationship(account.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to retrieve the relationship to this account: %w", err)
|
return fmt.Errorf("unable to retrieve the relationship to this account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(relationship, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.myAccount && s.showUserPreferences {
|
if s.myAccount && s.showUserPreferences {
|
||||||
preferences, err := gtsClient.GetUserPreferences()
|
preferences, err = gtsClient.GetUserPreferences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to retrieve the user preferences: %w", err)
|
return fmt.Errorf("unable to retrieve the user preferences: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(preferences, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.printer.PrintAccount(account, relationship, preferences)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +172,7 @@ func (s *ShowExecutor) showStatus(gtsClient *client.Client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(status, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintStatus(status)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -210,12 +216,12 @@ func (s *ShowExecutor) showTimeline(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(timeline.Statuses) == 0 {
|
if len(timeline.Statuses) == 0 {
|
||||||
fmt.Println("There are no statuses in this timeline.")
|
s.printer.PrintInfo("There are no statuses in this timeline.\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(timeline, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintStatusList(timeline)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -244,7 +250,7 @@ func (s *ShowExecutor) showList(gtsClient *client.Client) error {
|
||||||
list.Accounts = accountMap
|
list.Accounts = accountMap
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(list, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintList(list)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -256,18 +262,18 @@ func (s *ShowExecutor) showLists(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(lists) == 0 {
|
if len(lists) == 0 {
|
||||||
fmt.Println("You have no lists.")
|
s.printer.PrintInfo("You have no lists.\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(lists, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintLists(lists)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -278,16 +284,16 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(followers.Accounts) > 0 {
|
if len(followers.Accounts) > 0 {
|
||||||
utilities.Display(followers, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintAccountList(followers)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("There are no followers for this account or the list is hidden.")
|
s.printer.PrintInfo("There are no followers for this account (or the list is hidden).\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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.topLevelFlags.ConfigDir)
|
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -298,9 +304,9 @@ func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(following.Accounts) > 0 {
|
if len(following.Accounts) > 0 {
|
||||||
utilities.Display(following, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintAccountList(following)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("This account is not following anyone or the list is hidden.")
|
s.printer.PrintInfo("This account is not following anyone or the list is hidden.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -313,9 +319,9 @@ func (s *ShowExecutor) showBlocked(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(blocked.Accounts) > 0 {
|
if len(blocked.Accounts) > 0 {
|
||||||
utilities.Display(blocked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintAccountList(blocked)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("You have no blocked accounts.")
|
s.printer.PrintInfo("You have no blocked accounts.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -328,9 +334,9 @@ func (s *ShowExecutor) showBookmarks(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(bookmarks.Statuses) > 0 {
|
if len(bookmarks.Statuses) > 0 {
|
||||||
utilities.Display(bookmarks, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintStatusList(bookmarks)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("You have no bookmarks.")
|
s.printer.PrintInfo("You have no bookmarks.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -343,9 +349,9 @@ func (s *ShowExecutor) showLiked(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(liked.Statuses) > 0 {
|
if len(liked.Statuses) > 0 {
|
||||||
utilities.Display(liked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintStatusList(liked)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("You have no %s statuses.\n", s.resourceType)
|
s.printer.PrintInfo("You have no " + s.resourceType + " statuses.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -358,9 +364,9 @@ func (s *ShowExecutor) showFollowRequests(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(accounts.Accounts) > 0 {
|
if len(accounts.Accounts) > 0 {
|
||||||
utilities.Display(accounts, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintAccountList(accounts)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("You have no follow requests.")
|
s.printer.PrintInfo("You have no follow requests.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -376,7 +382,7 @@ func (s *ShowExecutor) showPoll(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to retrieve the poll: %w", err)
|
return fmt.Errorf("unable to retrieve the poll: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.Display(poll, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
s.printer.PrintPoll(poll)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,23 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SwitchExecutor struct {
|
type SwitchExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
configDir string
|
||||||
toResourceType string
|
toResourceType string
|
||||||
accountName string
|
accountName string
|
||||||
|
printer *printer.Printer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSwitchExecutor(tlf TopLevelFlags, name, summary string) *SwitchExecutor {
|
func NewSwitchExecutor(printer *printer.Printer, configDir, name, summary string) *SwitchExecutor {
|
||||||
switchExe := SwitchExecutor{
|
switchExe := SwitchExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
||||||
|
@ -51,11 +54,11 @@ func (s *SwitchExecutor) switchToAccount() error {
|
||||||
return NoAccountSpecifiedError{}
|
return NoAccountSpecifiedError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.UpdateCurrentAccount(s.accountName, s.topLevelFlags.ConfigDir); err != nil {
|
if err := config.UpdateCurrentAccount(s.accountName, s.configDir); 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("The current account is now set to %q.\n", s.accountName)
|
s.printer.PrintSuccess("The current account is now set to '" + s.accountName + "'.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@ package executor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
|
||||||
"strings"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
"text/tabwriter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type VersionExecutor struct {
|
type VersionExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
printer *printer.Printer
|
||||||
showFullVersion bool
|
showFullVersion bool
|
||||||
binaryVersion string
|
binaryVersion string
|
||||||
buildTime string
|
buildTime string
|
||||||
|
@ -20,9 +20,19 @@ type VersionExecutor struct {
|
||||||
gitCommit string
|
gitCommit string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVersionExecutor(name, summary, binaryVersion, buildTime, goVersion, gitCommit string) *VersionExecutor {
|
func NewVersionExecutor(
|
||||||
|
enbasPrinter *printer.Printer,
|
||||||
|
name,
|
||||||
|
summary,
|
||||||
|
binaryVersion,
|
||||||
|
buildTime,
|
||||||
|
goVersion,
|
||||||
|
gitCommit string,
|
||||||
|
) *VersionExecutor {
|
||||||
command := VersionExecutor{
|
command := VersionExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
|
|
||||||
|
printer: enbasPrinter,
|
||||||
binaryVersion: binaryVersion,
|
binaryVersion: binaryVersion,
|
||||||
buildTime: buildTime,
|
buildTime: buildTime,
|
||||||
goVersion: goVersion,
|
goVersion: goVersion,
|
||||||
|
@ -38,24 +48,7 @@ func NewVersionExecutor(name, summary, binaryVersion, buildTime, goVersion, gitC
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VersionExecutor) Execute() error {
|
func (v *VersionExecutor) Execute() error {
|
||||||
var builder strings.Builder
|
v.printer.PrintVersion(v.showFullVersion, v.binaryVersion, v.buildTime, v.goVersion, v.gitCommit)
|
||||||
|
|
||||||
if v.showFullVersion {
|
|
||||||
builder.WriteString("Enbas\n")
|
|
||||||
|
|
||||||
tableWriter := tabwriter.NewWriter(&builder, 0, 8, 0, '\t', 0)
|
|
||||||
|
|
||||||
tableWriter.Write([]byte(" Version:\t" + v.binaryVersion + "\n"))
|
|
||||||
tableWriter.Write([]byte(" Git commit:\t" + v.gitCommit + "\n"))
|
|
||||||
tableWriter.Write([]byte(" Go version:\t" + v.goVersion + "\n"))
|
|
||||||
tableWriter.Write([]byte(" Build date:\t" + v.buildTime + "\n"))
|
|
||||||
|
|
||||||
tableWriter.Flush()
|
|
||||||
} else {
|
|
||||||
builder.WriteString("Enbas " + v.binaryVersion + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Stdout.WriteString(builder.String())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,22 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WhoAmIExecutor struct {
|
type WhoAmIExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
printer *printer.Printer
|
||||||
|
configDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor {
|
func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string) *WhoAmIExecutor {
|
||||||
whoExe := WhoAmIExecutor{
|
whoExe := WhoAmIExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
topLevelFlags: tlf,
|
|
||||||
|
printer: printer,
|
||||||
|
configDir: configDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
|
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
|
||||||
|
@ -29,12 +33,12 @@ func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WhoAmIExecutor) Execute() error {
|
func (c *WhoAmIExecutor) Execute() error {
|
||||||
config, err := config.NewCredentialsConfigFromFile(c.topLevelFlags.ConfigDir)
|
config, err := config.NewCredentialsConfigFromFile(c.configDir)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("You are logged in as %q.\n", config.CurrentAccount)
|
c.printer.PrintInfo("You are logged in as '" + config.CurrentAccount + "'.\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
|
@ -63,59 +60,6 @@ type Field struct {
|
||||||
VerifiedAt string `json:"verified_at"`
|
VerifiedAt string `json:"verified_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Account) Display(noColor bool) string {
|
|
||||||
format := `
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s %d
|
|
||||||
%s %d
|
|
||||||
%s %d
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s %s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s`
|
|
||||||
|
|
||||||
metadata := ""
|
|
||||||
|
|
||||||
for _, field := range a.Fields {
|
|
||||||
metadata += fmt.Sprintf(
|
|
||||||
"\n %s: %s",
|
|
||||||
utilities.FieldFormat(noColor, field.Name),
|
|
||||||
utilities.ConvertHTMLToText(field.Value),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
format,
|
|
||||||
utilities.FullDisplayNameFormat(noColor, a.DisplayName, a.Acct),
|
|
||||||
utilities.HeaderFormat(noColor, "ACCOUNT ID:"),
|
|
||||||
a.ID,
|
|
||||||
utilities.HeaderFormat(noColor, "JOINED ON:"),
|
|
||||||
utilities.FormatDate(a.CreatedAt),
|
|
||||||
utilities.HeaderFormat(noColor, "STATS:"),
|
|
||||||
utilities.FieldFormat(noColor, "Followers:"), a.FollowersCount,
|
|
||||||
utilities.FieldFormat(noColor, "Following:"), a.FollowingCount,
|
|
||||||
utilities.FieldFormat(noColor, "Statuses:"), a.StatusCount,
|
|
||||||
utilities.HeaderFormat(noColor, "BIOGRAPHY:"),
|
|
||||||
utilities.WrapLines(utilities.ConvertHTMLToText(a.Note), "\n ", 80),
|
|
||||||
utilities.HeaderFormat(noColor, "METADATA:"),
|
|
||||||
metadata,
|
|
||||||
utilities.HeaderFormat(noColor, "ACCOUNT URL:"),
|
|
||||||
a.URL,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountRelationship struct {
|
type AccountRelationship struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
PrivateNote string `json:"note"`
|
PrivateNote string `json:"note"`
|
||||||
|
@ -133,53 +77,6 @@ type AccountRelationship struct {
|
||||||
ShowingReblogs bool `json:"showing_reblogs"`
|
ShowingReblogs bool `json:"showing_reblogs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AccountRelationship) Display(noColor bool) string {
|
|
||||||
format := `
|
|
||||||
%s
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t
|
|
||||||
%s: %t`
|
|
||||||
|
|
||||||
privateNoteFormat := `
|
|
||||||
%s
|
|
||||||
%s`
|
|
||||||
|
|
||||||
output := fmt.Sprintf(
|
|
||||||
format,
|
|
||||||
utilities.HeaderFormat(noColor, "YOUR RELATIONSHIP WITH THIS ACCOUNT:"),
|
|
||||||
utilities.FieldFormat(noColor, "Following"), a.Following,
|
|
||||||
utilities.FieldFormat(noColor, "Is following you"), a.FollowedBy,
|
|
||||||
utilities.FieldFormat(noColor, "A follow request was sent and is pending"), a.FollowRequested,
|
|
||||||
utilities.FieldFormat(noColor, "Received a pending follow request"), a.FollowRequestedBy,
|
|
||||||
utilities.FieldFormat(noColor, "Endorsed"), a.Endorsed,
|
|
||||||
utilities.FieldFormat(noColor, "Showing Reposts (boosts)"), a.ShowingReblogs,
|
|
||||||
utilities.FieldFormat(noColor, "Muted"), a.Muting,
|
|
||||||
utilities.FieldFormat(noColor, "Notifications muted"), a.MutingNotifications,
|
|
||||||
utilities.FieldFormat(noColor, "Blocking"), a.Blocking,
|
|
||||||
utilities.FieldFormat(noColor, "Is blocking you"), a.BlockedBy,
|
|
||||||
utilities.FieldFormat(noColor, "Blocking account's domain"), a.DomainBlocking,
|
|
||||||
)
|
|
||||||
|
|
||||||
if a.PrivateNote != "" {
|
|
||||||
output += "\n"
|
|
||||||
output += fmt.Sprintf(
|
|
||||||
privateNoteFormat,
|
|
||||||
utilities.HeaderFormat(noColor, "YOUR PRIVATE NOTE ABOUT THIS ACCOUNT:"),
|
|
||||||
utilities.WrapLines(a.PrivateNote, "\n ", 80),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountListType int
|
type AccountListType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -193,36 +90,3 @@ type AccountList struct {
|
||||||
Type AccountListType
|
Type AccountListType
|
||||||
Accounts []Account
|
Accounts []Account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AccountList) Display(noColor bool) string {
|
|
||||||
output := "\n"
|
|
||||||
|
|
||||||
switch a.Type {
|
|
||||||
case AccountListFollowers:
|
|
||||||
output += utilities.HeaderFormat(noColor, "Followed by:")
|
|
||||||
case AccountListFollowing:
|
|
||||||
output += utilities.HeaderFormat(noColor, "Following:")
|
|
||||||
case AccountListBlockedAccount:
|
|
||||||
output += utilities.HeaderFormat(noColor, "Blocked accounts:")
|
|
||||||
case AccountListFollowRequests:
|
|
||||||
output += utilities.HeaderFormat(noColor, "Accounts that have requested to follow you:")
|
|
||||||
default:
|
|
||||||
output += utilities.HeaderFormat(noColor, "Accounts:")
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Type == AccountListBlockedAccount {
|
|
||||||
for i := range a.Accounts {
|
|
||||||
output += fmt.Sprintf(
|
|
||||||
"\n • %s (%s)",
|
|
||||||
a.Accounts[i].Acct,
|
|
||||||
a.Accounts[i].ID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := range a.Accounts {
|
|
||||||
output += "\n • " + utilities.FullDisplayNameFormat(noColor, a.Accounts[i].DisplayName, a.Accounts[i].Acct)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,12 +4,6 @@
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InstanceV2 struct {
|
type InstanceV2 struct {
|
||||||
AccountDomain string `json:"account_domain"`
|
AccountDomain string `json:"account_domain"`
|
||||||
Configuration InstanceConfiguration `json:"configuration"`
|
Configuration InstanceConfiguration `json:"configuration"`
|
||||||
|
@ -116,48 +110,3 @@ type InstanceV2Usage struct {
|
||||||
type InstanceV2Users struct {
|
type InstanceV2Users struct {
|
||||||
ActiveMonth int `json:"active_month"`
|
ActiveMonth int `json:"active_month"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i InstanceV2) Display(noColor bool) string {
|
|
||||||
format := `
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
Running GoToSocial %s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s %s
|
|
||||||
%s %s
|
|
||||||
%s %s
|
|
||||||
`
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
format,
|
|
||||||
utilities.HeaderFormat(noColor, "INSTANCE TITLE:"),
|
|
||||||
i.Title,
|
|
||||||
utilities.HeaderFormat(noColor, "INSTANCE DESCRIPTION:"),
|
|
||||||
utilities.WrapLines(i.DescriptionText, "\n ", 80),
|
|
||||||
utilities.HeaderFormat(noColor, "DOMAIN:"),
|
|
||||||
i.Domain,
|
|
||||||
utilities.HeaderFormat(noColor, "TERMS AND CONDITIONS:"),
|
|
||||||
utilities.WrapLines(i.TermsText, "\n ", 80),
|
|
||||||
utilities.HeaderFormat(noColor, "VERSION:"),
|
|
||||||
i.Version,
|
|
||||||
utilities.HeaderFormat(noColor, "CONTACT:"),
|
|
||||||
utilities.FieldFormat(noColor, "Name:"),
|
|
||||||
i.Contact.Account.DisplayName,
|
|
||||||
utilities.FieldFormat(noColor, "Username:"),
|
|
||||||
i.Contact.Account.Acct,
|
|
||||||
utilities.FieldFormat(noColor, "Email:"),
|
|
||||||
i.Contact.Email,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ package model
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListRepliesPolicy int
|
type ListRepliesPolicy int
|
||||||
|
@ -107,53 +105,3 @@ type List struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Accounts map[string]string
|
Accounts map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l List) Display(noColor bool) string {
|
|
||||||
format := `
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s
|
|
||||||
%s
|
|
||||||
|
|
||||||
%s`
|
|
||||||
|
|
||||||
output := fmt.Sprintf(
|
|
||||||
format,
|
|
||||||
utilities.HeaderFormat(noColor, "LIST TITLE:"), l.Title,
|
|
||||||
utilities.HeaderFormat(noColor, "LIST ID:"), l.ID,
|
|
||||||
utilities.HeaderFormat(noColor, "REPLIES POLICY:"), l.RepliesPolicy,
|
|
||||||
utilities.HeaderFormat(noColor, "ADDED ACCOUNTS:"),
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(l.Accounts) > 0 {
|
|
||||||
for acct, name := range l.Accounts {
|
|
||||||
output += "\n • " + utilities.FullDisplayNameFormat(noColor, name, acct)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
output += "\n None"
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "\n"
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
type Lists []List
|
|
||||||
|
|
||||||
func (l Lists) Display(noColor bool) string {
|
|
||||||
output := "\n" + utilities.HeaderFormat(noColor, "LISTS")
|
|
||||||
|
|
||||||
for i := range l {
|
|
||||||
output += fmt.Sprintf(
|
|
||||||
"\n • %s (%s)",
|
|
||||||
l[i].Title,
|
|
||||||
l[i].ID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,13 +5,7 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Poll struct {
|
type Poll struct {
|
||||||
|
@ -31,93 +25,3 @@ type PollOption struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
VotesCount int `json:"votes_count"`
|
VotesCount int `json:"votes_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Poll) Display(noColor bool) string {
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
indent := " "
|
|
||||||
|
|
||||||
builder.WriteString(
|
|
||||||
utilities.HeaderFormat(noColor, "POLL ID:") +
|
|
||||||
"\n" + indent + p.ID +
|
|
||||||
"\n\n" + utilities.HeaderFormat(noColor, "OPTIONS:"),
|
|
||||||
)
|
|
||||||
|
|
||||||
displayPollContent(&builder, p, noColor, indent)
|
|
||||||
|
|
||||||
builder.WriteString(
|
|
||||||
"\n\n" +
|
|
||||||
utilities.HeaderFormat(noColor, "MULTIPLE CHOICES ALLOWED:") +
|
|
||||||
"\n" + indent + strconv.FormatBool(p.Multiple) +
|
|
||||||
"\n\n" +
|
|
||||||
utilities.HeaderFormat(noColor, "YOU VOTED:") +
|
|
||||||
"\n" + indent + strconv.FormatBool(p.Voted),
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(p.OwnVotes) > 0 {
|
|
||||||
builder.WriteString("\n\n" + utilities.HeaderFormat(noColor, "YOUR VOTES:"))
|
|
||||||
|
|
||||||
for _, vote := range p.OwnVotes {
|
|
||||||
builder.WriteString("\n" + indent + "[" + strconv.Itoa(vote) + "] " + p.Options[vote].Title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(
|
|
||||||
"\n\n" +
|
|
||||||
utilities.HeaderFormat(noColor, "EXPIRED:") +
|
|
||||||
"\n" + indent + strconv.FormatBool(p.Expired),
|
|
||||||
)
|
|
||||||
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayPollContent(writer io.StringWriter, poll Poll, noColor bool, indent string) {
|
|
||||||
for ind, option := range poll.Options {
|
|
||||||
var percentage int
|
|
||||||
var calculate float64
|
|
||||||
|
|
||||||
if poll.VotesCount == 0 {
|
|
||||||
percentage = 0
|
|
||||||
} else {
|
|
||||||
calculate = float64(option.VotesCount) / float64(poll.VotesCount)
|
|
||||||
percentage = int(math.Floor(100 * calculate))
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteString("\n\n" + indent + "[" + strconv.Itoa(ind) + "] " + option.Title)
|
|
||||||
drawPollMeter(writer, noColor, calculate, 80, indent)
|
|
||||||
|
|
||||||
writer.WriteString(
|
|
||||||
"\n" + indent + strconv.Itoa(option.VotesCount) + " votes " +
|
|
||||||
"(" + strconv.Itoa(percentage) + "%)",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteString(
|
|
||||||
"\n\n" +
|
|
||||||
indent + utilities.FieldFormat(noColor, "Total votes:") + " " + strconv.Itoa(poll.VotesCount) +
|
|
||||||
"\n" + indent + utilities.FieldFormat(noColor, "Poll ID:") + " " + poll.ID +
|
|
||||||
"\n" + indent + utilities.FieldFormat(noColor, "Poll is open until:") + " " + utilities.FormatTime(poll.ExpiredAt),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func drawPollMeter(writer io.StringWriter, noColor bool, calculated float64, limit int, indent string) {
|
|
||||||
numVoteBlocks := int(math.Floor(float64(limit) * calculated))
|
|
||||||
numBackgroundBlocks := limit - numVoteBlocks
|
|
||||||
blockChar := "\u2501"
|
|
||||||
voteBlockColor := "\033[32;1m"
|
|
||||||
backgroundBlockColor := "\033[90m"
|
|
||||||
|
|
||||||
if noColor {
|
|
||||||
voteBlockColor = "\033[0m"
|
|
||||||
|
|
||||||
if numVoteBlocks == 0 {
|
|
||||||
numVoteBlocks = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteString("\n" + indent + voteBlockColor + strings.Repeat(blockChar, numVoteBlocks) + "\033[0m")
|
|
||||||
|
|
||||||
if !noColor {
|
|
||||||
writer.WriteString(backgroundBlockColor + strings.Repeat(blockChar, numBackgroundBlocks) + "\033[0m")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,12 +4,6 @@
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Preferences struct {
|
type Preferences struct {
|
||||||
PostingDefaultVisibility string `json:"posting:default:visibility"`
|
PostingDefaultVisibility string `json:"posting:default:visibility"`
|
||||||
PostingDefaultSensitive bool `json:"posting:default:sensitive"`
|
PostingDefaultSensitive bool `json:"posting:default:sensitive"`
|
||||||
|
@ -18,19 +12,3 @@ type Preferences struct {
|
||||||
ReadingExpandSpoilers bool `json:"reading:expand:spoilers"`
|
ReadingExpandSpoilers bool `json:"reading:expand:spoilers"`
|
||||||
ReadingAutoplayGifs bool `json:"reading:autoplay:gifs"`
|
ReadingAutoplayGifs bool `json:"reading:autoplay:gifs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Preferences) Display(noColor bool) string {
|
|
||||||
format := `
|
|
||||||
%s
|
|
||||||
%s: %s
|
|
||||||
%s: %s
|
|
||||||
%s: %t`
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
format,
|
|
||||||
utilities.HeaderFormat(noColor, "YOUR PREFERENCES:"),
|
|
||||||
utilities.FieldFormat(noColor, "Default post language"), p.PostingDefaultLanguage,
|
|
||||||
utilities.FieldFormat(noColor, "Default post visibility"), p.PostingDefaultVisibility,
|
|
||||||
utilities.FieldFormat(noColor, "Mark posts as sensitive by default"), p.PostingDefaultSensitive,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,11 +5,7 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
@ -139,86 +135,7 @@ type MediaDimensions struct {
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Status) Display(noColor bool) string {
|
|
||||||
indent := " "
|
|
||||||
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
// The account information
|
|
||||||
builder.WriteString(utilities.FullDisplayNameFormat(noColor, s.Account.DisplayName, s.Account.Acct) + "\n\n")
|
|
||||||
|
|
||||||
// The content of the status.
|
|
||||||
builder.WriteString(utilities.HeaderFormat(noColor, "CONTENT:"))
|
|
||||||
builder.WriteString(utilities.WrapLines(utilities.ConvertHTMLToText(s.Content), "\n ", 80))
|
|
||||||
|
|
||||||
// If a poll exists in a status, write the contents to the builder.
|
|
||||||
if s.Poll != nil {
|
|
||||||
displayPollContent(&builder, *s.Poll, noColor, indent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ID of the status
|
|
||||||
builder.WriteString("\n\n" + utilities.HeaderFormat(noColor, "STATUS ID:") + "\n" + indent + s.ID)
|
|
||||||
|
|
||||||
// Status creation time
|
|
||||||
builder.WriteString("\n\n" + utilities.HeaderFormat(noColor, "CREATED AT:") + "\n" + indent + utilities.FormatTime(s.CreatedAt))
|
|
||||||
|
|
||||||
// Status stats
|
|
||||||
builder.WriteString(
|
|
||||||
"\n\n" +
|
|
||||||
utilities.HeaderFormat(noColor, "STATS:") +
|
|
||||||
"\n" + indent + utilities.FieldFormat(noColor, "Boosts: ") + strconv.Itoa(s.ReblogsCount) +
|
|
||||||
"\n" + indent + utilities.FieldFormat(noColor, "Likes: ") + strconv.Itoa(s.FavouritesCount) +
|
|
||||||
"\n" + indent + utilities.FieldFormat(noColor, "Replies: ") + strconv.Itoa(s.RepliesCount),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Status visibility
|
|
||||||
builder.WriteString("\n\n" + utilities.HeaderFormat(noColor, "VISIBILITY:") + "\n" + indent + s.Visibility.String())
|
|
||||||
|
|
||||||
// Status URL
|
|
||||||
builder.WriteString("\n\n" + utilities.HeaderFormat(noColor, "URL:") + "\n" + indent + s.URL)
|
|
||||||
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type StatusList struct {
|
type StatusList struct {
|
||||||
Name string
|
Name string
|
||||||
Statuses []Status
|
Statuses []Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StatusList) Display(noColor bool) string {
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
separator := strings.Repeat("─", 80)
|
|
||||||
|
|
||||||
builder.WriteString(utilities.HeaderFormat(noColor, s.Name) + "\n")
|
|
||||||
|
|
||||||
for _, status := range s.Statuses {
|
|
||||||
builder.WriteString("\n" + utilities.FullDisplayNameFormat(noColor, status.Account.DisplayName, status.Account.Acct) + "\n")
|
|
||||||
|
|
||||||
statusID := status.ID
|
|
||||||
createdAt := status.CreatedAt
|
|
||||||
|
|
||||||
if status.Reblog != nil {
|
|
||||||
builder.WriteString("reposted this status from " + utilities.FullDisplayNameFormat(noColor, status.Reblog.Account.DisplayName, status.Reblog.Account.Acct) + "\n")
|
|
||||||
statusID = status.Reblog.ID
|
|
||||||
createdAt = status.Reblog.CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(utilities.WrapLines(utilities.ConvertHTMLToText(status.Content), "\n", 80))
|
|
||||||
|
|
||||||
if status.Poll != nil {
|
|
||||||
displayPollContent(&builder, *status.Poll, noColor, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(
|
|
||||||
"\n\n" +
|
|
||||||
utilities.FieldFormat(noColor, "Status ID:") + " " + statusID + "\t" +
|
|
||||||
utilities.FieldFormat(noColor, "Created at:") + " " + utilities.FormatTime(createdAt) +
|
|
||||||
"\n",
|
|
||||||
)
|
|
||||||
|
|
||||||
builder.WriteString(separator + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
137
internal/printer/account.go
Normal file
137
internal/printer/account.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintAccount(account model.Account, relationship *model.AccountRelationship, preferences *model.Preferences) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.fullDisplayNameFormat(account.DisplayName, account.Acct))
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("ACCOUNT ID:"))
|
||||||
|
builder.WriteString("\n" + account.ID)
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("JOINED ON:"))
|
||||||
|
builder.WriteString("\n" + p.formatDate(account.CreatedAt))
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("STATS:"))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Followers:"))
|
||||||
|
builder.WriteString(" " + strconv.Itoa(account.FollowersCount))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Following:"))
|
||||||
|
builder.WriteString(" " + strconv.Itoa(account.FollowingCount))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Statuses:"))
|
||||||
|
builder.WriteString(" " + strconv.Itoa(account.StatusCount))
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("BIOGRAPHY:"))
|
||||||
|
builder.WriteString(utilities.WrapLines(utilities.ConvertHTMLToText(account.Note), "\n", p.maxTerminalWidth))
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("METADATA:"))
|
||||||
|
|
||||||
|
for _, field := range account.Fields {
|
||||||
|
builder.WriteString("\n" + p.fieldFormat(field.Name) + ": " + field.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("ACCOUNT URL:"))
|
||||||
|
builder.WriteString("\n" + account.URL)
|
||||||
|
|
||||||
|
if relationship != nil {
|
||||||
|
builder.WriteString(p.accountRelationship(relationship))
|
||||||
|
}
|
||||||
|
|
||||||
|
if preferences != nil {
|
||||||
|
builder.WriteString(p.userPreferences(preferences))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\n")
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
dananglin marked this conversation as resolved
Outdated
|
|||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) accountRelationship(relationship *model.AccountRelationship) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("YOUR RELATIONSHIP WITH THIS ACCOUNT:"))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Following:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.Following))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Is following you:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.FollowedBy))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("A follow request was sent and is pending:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.FollowRequested))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Received a pending follow request:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.FollowRequestedBy))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Endorsed:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.Endorsed))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Showing Reposts (boosts):"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.ShowingReblogs))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Muted:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.Muting))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Notifications muted:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.MutingNotifications))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Blocking:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.Blocking))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Is blocking you:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.BlockedBy))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Blocking account's domain:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(relationship.DomainBlocking))
|
||||||
|
|
||||||
|
if relationship.PrivateNote != "" {
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("YOUR PRIVATE NOTE ABOUT THIS ACCOUNT:"))
|
||||||
|
builder.WriteString("\n" + utilities.WrapLines(relationship.PrivateNote, "\n", p.maxTerminalWidth))
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) userPreferences(preferences *model.Preferences) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("YOUR PREFERENCES:"))
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Default post language:"))
|
||||||
|
builder.WriteString(" " + preferences.PostingDefaultLanguage)
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Default post visibility:"))
|
||||||
|
builder.WriteString(" " + preferences.PostingDefaultVisibility)
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Mark posts as sensitive by default:"))
|
||||||
|
builder.WriteString(" " + strconv.FormatBool(preferences.PostingDefaultSensitive))
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintAccountList(list model.AccountList) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n")
|
||||||
|
|
||||||
|
switch list.Type {
|
||||||
|
case model.AccountListFollowers:
|
||||||
|
builder.WriteString(p.headerFormat("Followed by:"))
|
||||||
|
case model.AccountListFollowing:
|
||||||
|
builder.WriteString(p.headerFormat("Following:"))
|
||||||
|
case model.AccountListBlockedAccount:
|
||||||
|
builder.WriteString(p.headerFormat("Blocked accounts:"))
|
||||||
|
case model.AccountListFollowRequests:
|
||||||
|
builder.WriteString(p.headerFormat("Accounts that have requested to follow you:"))
|
||||||
|
default:
|
||||||
|
builder.WriteString(p.headerFormat("Accounts:"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if list.Type == model.AccountListBlockedAccount {
|
||||||
|
for ind := range list.Accounts {
|
||||||
|
builder.WriteString("\n" + p.bullet + " " + list.Accounts[ind].Acct + " (" + list.Accounts[ind].ID + ")")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ind := range list.Accounts {
|
||||||
|
builder.WriteString("\n" + p.bullet + " " + p.fullDisplayNameFormat(list.Accounts[ind].DisplayName, list.Accounts[ind].Acct))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n")
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
dananglin marked this conversation as resolved
Outdated
dananglin
commented
Should be p.print() Should be p.print()
|
|||||||
|
}
|
43
internal/printer/instance.go
Normal file
43
internal/printer/instance.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintInstance(instance model.InstanceV2) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.headerFormat("INSTANCE TITLE:"))
|
||||||
|
builder.WriteString("\n" + instance.Title)
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("INSTANCE DESCRIPTION:"))
|
||||||
|
builder.WriteString("\n" + utilities.WrapLines(instance.DescriptionText, "\n", p.maxTerminalWidth))
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("DOMAIN:"))
|
||||||
|
builder.WriteString("\n" + instance.Domain)
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("TERMS AND CONDITIONS:"))
|
||||||
|
builder.WriteString("\n" + utilities.WrapLines(instance.TermsText, "\n ", p.maxTerminalWidth))
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("VERSION:"))
|
||||||
|
builder.WriteString("\nRunning GoToSocial " + instance.Version)
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("CONTACT:"))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Name:"))
|
||||||
|
builder.WriteString(" " + instance.Contact.Account.DisplayName)
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Username:"))
|
||||||
|
builder.WriteString(" " + instance.Contact.Account.Acct)
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Email:"))
|
||||||
|
builder.WriteString(" " + instance.Contact.Email)
|
||||||
|
|
||||||
|
builder.WriteString("\n\n")
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
|
}
|
49
internal/printer/list.go
Normal file
49
internal/printer/list.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintList(list model.List) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.headerFormat("LIST TITLE:") + "\n")
|
||||||
|
builder.WriteString(list.Title + "\n\n")
|
||||||
|
builder.WriteString(p.headerFormat("LIST ID:") + "\n")
|
||||||
|
builder.WriteString(list.ID + "\n\n")
|
||||||
|
builder.WriteString(p.headerFormat("REPLIES POLICY:") + "\n")
|
||||||
|
builder.WriteString(list.RepliesPolicy.String() + "\n\n")
|
||||||
|
builder.WriteString(p.headerFormat("ADDED ACCOUNTS:"))
|
||||||
|
|
||||||
|
if len(list.Accounts) > 0 {
|
||||||
|
for acct, name := range list.Accounts {
|
||||||
|
builder.WriteString("\n" + p.bullet + " " + p.fullDisplayNameFormat(name, acct))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.WriteString("\n" + "None")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n")
|
||||||
|
|
||||||
|
printToStdout(builder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintLists(lists []model.List) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.headerFormat("LISTS"))
|
||||||
|
|
||||||
|
for i := range lists {
|
||||||
|
builder.WriteString("\n" + p.bullet + " " + lists[i].Title + " (" + lists[i].ID + ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n")
|
||||||
|
|
||||||
|
printToStdout(builder.String())
|
||||||
|
}
|
95
internal/printer/poll.go
Normal file
95
internal/printer/poll.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintPoll(poll model.Poll) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("\n" + p.headerFormat("POLL ID:"))
|
||||||
|
builder.WriteString("\n" + poll.ID)
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("OPTIONS:"))
|
||||||
|
builder.WriteString(p.pollOptions(poll))
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("MULTIPLE CHOICES ALLOWED:"))
|
||||||
|
builder.WriteString("\n" + strconv.FormatBool(poll.Multiple))
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("YOU VOTED:"))
|
||||||
|
builder.WriteString("\n" + strconv.FormatBool(poll.Voted))
|
||||||
|
|
||||||
|
if len(poll.OwnVotes) > 0 {
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("YOUR VOTES:"))
|
||||||
|
|
||||||
|
for _, vote := range poll.OwnVotes {
|
||||||
|
builder.WriteString("\n" + "[" + strconv.Itoa(vote) + "] " + poll.Options[vote].Title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("EXPIRED:"))
|
||||||
|
builder.WriteString("\n" + strconv.FormatBool(poll.Expired))
|
||||||
|
builder.WriteString("\n\n")
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) pollOptions(poll model.Poll) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
for ind, option := range poll.Options {
|
||||||
|
var (
|
||||||
|
votage float64
|
||||||
|
percentage int
|
||||||
|
)
|
||||||
|
|
||||||
|
if poll.VotesCount == 0 {
|
||||||
|
percentage = 0
|
||||||
|
} else {
|
||||||
|
votage = float64(option.VotesCount) / float64(poll.VotesCount)
|
||||||
|
percentage = int(math.Floor(100 * votage))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + "[" + strconv.Itoa(ind) + "] " + option.Title)
|
||||||
|
builder.WriteString(p.pollMeter(votage))
|
||||||
|
builder.WriteString("\n" + strconv.Itoa(option.VotesCount) + " votes " + "(" + strconv.Itoa(percentage) + "%)")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\n" + p.fieldFormat("Total votes:") + " " + strconv.Itoa(poll.VotesCount))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Poll ID:") + " " + poll.ID)
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Poll is open until:") + " " + p.formatDateTime(poll.ExpiredAt))
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) pollMeter(votage float64) string {
|
||||||
|
numVoteBlocks := int(math.Floor(float64(p.maxTerminalWidth) * votage))
|
||||||
|
numBackgroundBlocks := p.maxTerminalWidth - numVoteBlocks
|
||||||
|
|
||||||
|
voteBlockColor := p.theme.boldgreen
|
||||||
|
backgroundBlockColor := p.theme.grey
|
||||||
|
|
||||||
|
if p.noColor {
|
||||||
|
voteBlockColor = p.theme.reset
|
||||||
|
|
||||||
|
if numVoteBlocks == 0 {
|
||||||
|
numVoteBlocks = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meter := "\n" + voteBlockColor + strings.Repeat(p.pollMeterSymbol, numVoteBlocks) + p.theme.reset
|
||||||
|
|
||||||
|
if !p.noColor {
|
||||||
|
meter += backgroundBlockColor + strings.Repeat(p.pollMeterSymbol, numBackgroundBlocks) + p.theme.reset
|
||||||
|
}
|
||||||
|
|
||||||
|
return meter
|
||||||
|
}
|
185
internal/printer/printer.go
Normal file
185
internal/printer/printer.go
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minTerminalWidth = 40
|
||||||
|
)
|
||||||
|
|
||||||
|
type theme struct {
|
||||||
|
reset string
|
||||||
|
boldblue string
|
||||||
|
boldmagenta string
|
||||||
|
green string
|
||||||
|
boldgreen string
|
||||||
|
grey string
|
||||||
|
red string
|
||||||
|
boldred string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Printer struct {
|
||||||
|
theme theme
|
||||||
|
noColor bool
|
||||||
|
maxTerminalWidth int
|
||||||
|
pager string
|
||||||
|
statusSeparator string
|
||||||
|
bullet string
|
||||||
|
pollMeterSymbol string
|
||||||
|
successSymbol string
|
||||||
|
failureSymbol string
|
||||||
|
dateFormat string
|
||||||
|
dateTimeFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrinter(
|
||||||
|
noColor bool,
|
||||||
|
pager string,
|
||||||
|
maxTerminalWidth int,
|
||||||
|
) *Printer {
|
||||||
|
theme := theme{
|
||||||
|
reset: "\033[0m",
|
||||||
|
boldblue: "\033[34;1m",
|
||||||
|
boldmagenta: "\033[35;1m",
|
||||||
|
green: "\033[32m",
|
||||||
|
boldgreen: "\033[32;1m",
|
||||||
|
grey: "\033[90m",
|
||||||
|
red: "\033[31m",
|
||||||
|
boldred: "\033[31;1m",
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxTerminalWidth < minTerminalWidth {
|
||||||
|
maxTerminalWidth = minTerminalWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Printer{
|
||||||
|
noColor: noColor,
|
||||||
|
maxTerminalWidth: maxTerminalWidth,
|
||||||
|
pager: pager,
|
||||||
|
statusSeparator: strings.Repeat("\u2501", maxTerminalWidth),
|
||||||
|
bullet: "\u2022",
|
||||||
|
pollMeterSymbol: "\u2501",
|
||||||
|
successSymbol: "\u2714",
|
||||||
|
failureSymbol: "\u2717",
|
||||||
|
dateFormat: "02 Jan 2006",
|
||||||
|
dateTimeFormat: "02 Jan 2006, 15:04 (MST)",
|
||||||
|
theme: theme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintSuccess(text string) {
|
||||||
|
success := p.theme.boldgreen + p.successSymbol + p.theme.reset
|
||||||
|
if p.noColor {
|
||||||
|
success = p.successSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
printToStdout(success + " " + text + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintFailure(text string) {
|
||||||
|
failure := p.theme.boldred + p.failureSymbol + p.theme.reset
|
||||||
|
if p.noColor {
|
||||||
|
failure = p.failureSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
printToStderr(failure + " " + text + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintInfo(text string) {
|
||||||
|
printToStdout(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) headerFormat(text string) string {
|
||||||
|
if p.noColor {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.theme.boldblue + text + p.theme.reset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) fieldFormat(text string) string {
|
||||||
|
if p.noColor {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.theme.green + text + p.theme.reset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) fullDisplayNameFormat(displayName, acct string) string {
|
||||||
|
// use this pattern to remove all emoji strings
|
||||||
|
pattern := regexp.MustCompile(`\s:[A-Za-z0-9_]*:`)
|
||||||
|
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
if p.noColor {
|
||||||
|
builder.WriteString(pattern.ReplaceAllString(displayName, ""))
|
||||||
|
} else {
|
||||||
|
builder.WriteString(p.theme.boldmagenta + pattern.ReplaceAllString(displayName, "") + p.theme.reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(" (@" + acct + ")")
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) formatDate(date time.Time) string {
|
||||||
|
return date.Local().Format(p.dateFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) formatDateTime(date time.Time) string {
|
||||||
|
return date.Local().Format(p.dateTimeFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) print(text string) {
|
||||||
|
if p.pager == "" {
|
||||||
|
printToStdout(text)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdSplit := strings.Split(p.pager, " ")
|
||||||
|
|
||||||
|
pager := new(exec.Cmd)
|
||||||
|
|
||||||
|
if len(cmdSplit) == 1 {
|
||||||
|
pager = exec.Command(cmdSplit[0]) //nolint:gosec
|
||||||
|
} else {
|
||||||
|
pager = exec.Command(cmdSplit[0], cmdSplit[1:]...) //nolint:gosec
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe, err := pager.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
printToStdout(text)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pager.Stdout = os.Stdout
|
||||||
|
pager.Stderr = os.Stderr
|
||||||
|
|
||||||
|
_ = pager.Start()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = pipe.Close()
|
||||||
|
_ = pager.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, _ = pipe.Write([]byte(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func printToStdout(text string) {
|
||||||
|
os.Stdout.WriteString(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printToStderr(text string) {
|
||||||
|
os.Stderr.WriteString(text)
|
||||||
|
}
|
97
internal/printer/status.go
Normal file
97
internal/printer/status.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintStatus(status model.Status) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
// The account information
|
||||||
|
builder.WriteString("\n" + p.fullDisplayNameFormat(status.Account.DisplayName, status.Account.Acct))
|
||||||
|
|
||||||
|
// The content of the status.
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("CONTENT:"))
|
||||||
|
builder.WriteString(utilities.WrapLines(utilities.ConvertHTMLToText(status.Content), "\n", p.maxTerminalWidth))
|
||||||
|
|
||||||
|
// If a poll exists in a status, write the contents to the builder.
|
||||||
|
if status.Poll != nil {
|
||||||
|
builder.WriteString(p.pollOptions(*status.Poll))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ID of the status
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("STATUS ID:"))
|
||||||
|
builder.WriteString("\n" + status.ID)
|
||||||
|
|
||||||
|
// Status creation time
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("CREATED AT:"))
|
||||||
|
builder.WriteString("\n" + p.formatDateTime(status.CreatedAt))
|
||||||
|
|
||||||
|
// Status stats
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("STATS:"))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Boosts: ") + strconv.Itoa(status.ReblogsCount))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Likes: ") + strconv.Itoa(status.FavouritesCount))
|
||||||
|
builder.WriteString("\n" + p.fieldFormat("Replies: ") + strconv.Itoa(status.RepliesCount))
|
||||||
|
|
||||||
|
// Status visibility
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("VISIBILITY:"))
|
||||||
|
builder.WriteString("\n" + status.Visibility.String())
|
||||||
|
|
||||||
|
// Status URL
|
||||||
|
builder.WriteString("\n\n" + p.headerFormat("URL:"))
|
||||||
|
builder.WriteString("\n" + status.URL)
|
||||||
|
builder.WriteString("\n\n")
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) PrintStatusList(list model.StatusList) {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString(p.headerFormat(list.Name) + "\n")
|
||||||
|
|
||||||
|
for _, status := range list.Statuses {
|
||||||
|
builder.WriteString("\n" + p.fullDisplayNameFormat(status.Account.DisplayName, status.Account.Acct))
|
||||||
|
|
||||||
|
statusID := status.ID
|
||||||
|
createdAt := status.CreatedAt
|
||||||
|
|
||||||
|
if status.Reblog != nil {
|
||||||
|
builder.WriteString(utilities.WrapLines(
|
||||||
|
"\n"+
|
||||||
|
"reposted this status from "+
|
||||||
|
p.fullDisplayNameFormat(status.Reblog.Account.DisplayName, status.Reblog.Account.Acct),
|
||||||
|
"\n",
|
||||||
|
p.maxTerminalWidth,
|
||||||
|
))
|
||||||
|
|
||||||
|
statusID = status.Reblog.ID
|
||||||
|
createdAt = status.Reblog.CreatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(utilities.WrapLines(utilities.ConvertHTMLToText(status.Content), "\n", p.maxTerminalWidth))
|
||||||
|
|
||||||
|
if status.Poll != nil {
|
||||||
|
builder.WriteString(p.pollOptions(*status.Poll))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(
|
||||||
|
"\n\n" +
|
||||||
|
p.fieldFormat("Status ID:") + " " + statusID + "\t" +
|
||||||
|
p.fieldFormat("Created at:") + " " + p.formatDateTime(createdAt) +
|
||||||
|
"\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.WriteString(p.statusSeparator + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print(builder.String())
|
||||||
|
}
|
33
internal/printer/version.go
Normal file
33
internal/printer/version.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Printer) PrintVersion(showFullVersion bool, binaryVersion, buildTime, goVersion, gitCommit string) {
|
||||||
|
if !showFullVersion {
|
||||||
|
printToStdout("Enbas " + binaryVersion + "\n")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString(p.headerFormat("Enbas") + "\n\n")
|
||||||
|
|
||||||
|
tableWriter := tabwriter.NewWriter(&builder, 0, 4, 1, ' ', 0)
|
||||||
|
|
||||||
|
_, _ = tableWriter.Write([]byte(p.fieldFormat("Version:") + "\t" + binaryVersion + "\n"))
|
||||||
|
_, _ = tableWriter.Write([]byte(p.fieldFormat("Git commit:") + "\t" + gitCommit + "\n"))
|
||||||
|
_, _ = tableWriter.Write([]byte(p.fieldFormat("Go version:") + "\t" + goVersion + "\n"))
|
||||||
|
_, _ = tableWriter.Write([]byte(p.fieldFormat("Build date:") + "\t" + buildTime + "\n"))
|
||||||
|
|
||||||
|
tableWriter.Flush()
|
||||||
|
|
||||||
|
printToStdout(builder.String())
|
||||||
|
}
|
|
@ -1,53 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package utilities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Displayer interface {
|
|
||||||
Display(noColor bool) string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Display(displayer Displayer, noColor bool, pagerCommand string) {
|
|
||||||
if pagerCommand == "" {
|
|
||||||
os.Stdout.WriteString(displayer.Display(noColor) + "\n")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
split := strings.Split(pagerCommand, " ")
|
|
||||||
|
|
||||||
pager := new(exec.Cmd)
|
|
||||||
|
|
||||||
if len(split) == 1 {
|
|
||||||
pager = exec.Command(split[0]) //nolint:gosec
|
|
||||||
} else {
|
|
||||||
pager = exec.Command(split[0], split[1:]...) //nolint:gosec
|
|
||||||
}
|
|
||||||
|
|
||||||
pipe, err := pager.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
os.Stdout.WriteString(displayer.Display(noColor) + "\n")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pager.Stdout = os.Stdout
|
|
||||||
pager.Stderr = os.Stderr
|
|
||||||
|
|
||||||
_ = pager.Start()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = pipe.Close()
|
|
||||||
_ = pager.Wait()
|
|
||||||
}()
|
|
||||||
|
|
||||||
fmt.Fprintln(pipe, displayer.Display(noColor)+"\n")
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package utilities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
reset = "\033[0m"
|
|
||||||
boldblue = "\033[34;1m"
|
|
||||||
boldmagenta = "\033[35;1m"
|
|
||||||
green = "\033[32m"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeaderFormat(noColor bool, text string) string {
|
|
||||||
if noColor {
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
return boldblue + text + reset
|
|
||||||
}
|
|
||||||
|
|
||||||
func FieldFormat(noColor bool, text string) string {
|
|
||||||
if noColor {
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
return green + text + reset
|
|
||||||
}
|
|
||||||
|
|
||||||
func FullDisplayNameFormat(noColor bool, displayName, acct string) string {
|
|
||||||
// use this pattern to remove all emoji strings
|
|
||||||
pattern := regexp.MustCompile(`\s:[A-Za-z0-9_]*:`)
|
|
||||||
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
if noColor {
|
|
||||||
builder.WriteString(pattern.ReplaceAllString(displayName, ""))
|
|
||||||
} else {
|
|
||||||
builder.WriteString(boldmagenta + pattern.ReplaceAllString(displayName, "") + reset)
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(" (@" + acct + ")")
|
|
||||||
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatDate(date time.Time) string {
|
|
||||||
return date.Local().Format("02 Jan 2006")
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatTime(date time.Time) string {
|
|
||||||
return date.Local().Format("02 Jan 2006, 15:04 (MST)")
|
|
||||||
}
|
|
Loading…
Reference in a new issue
Should be p.print()