Compare commits
4 commits
fcc08c1eb4
...
09cd13a2f7
Author | SHA1 | Date | |
---|---|---|---|
09cd13a2f7 | |||
d842233c98 | |||
947b1b8c46 | |||
f73f1f5872 |
23 changed files with 746 additions and 442 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -87,39 +88,52 @@ func run() error {
|
|||
command := flag.Arg(0)
|
||||
args := flag.Args()[1:]
|
||||
|
||||
enbasPrinter := printer.NewPrinter(
|
||||
*topLevelFlags.NoColor,
|
||||
topLevelFlags.Pager,
|
||||
80,
|
||||
)
|
||||
|
||||
executorMap := map[string]executor.Executor{
|
||||
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandAccept,
|
||||
executor.CommandSummaryLookup(executor.CommandAccept),
|
||||
),
|
||||
executor.CommandAdd: executor.NewAddExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandAdd,
|
||||
executor.CommandSummaryLookup(executor.CommandAdd),
|
||||
),
|
||||
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandBlock,
|
||||
executor.CommandSummaryLookup(executor.CommandBlock),
|
||||
),
|
||||
executor.CommandCreate: executor.NewCreateExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandCreate,
|
||||
executor.CommandSummaryLookup(executor.CommandCreate),
|
||||
),
|
||||
executor.CommandDelete: executor.NewDeleteExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandDelete,
|
||||
executor.CommandSummaryLookup(executor.CommandDelete),
|
||||
),
|
||||
executor.CommandEdit: executor.NewEditExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandEdit,
|
||||
executor.CommandSummaryLookup(executor.CommandEdit),
|
||||
),
|
||||
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandFollow,
|
||||
executor.CommandSummaryLookup(executor.CommandFollow),
|
||||
),
|
||||
|
@ -129,7 +143,8 @@ func run() error {
|
|||
executor.CommandSummaryLookup(executor.CommandLogin),
|
||||
),
|
||||
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandReject,
|
||||
executor.CommandSummaryLookup(executor.CommandReject),
|
||||
),
|
||||
|
@ -139,26 +154,31 @@ func run() error {
|
|||
executor.CommandSummaryLookup(executor.CommandRemove),
|
||||
),
|
||||
executor.CommandSwitch: executor.NewSwitchExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandSwitch,
|
||||
executor.CommandSummaryLookup(executor.CommandSwitch),
|
||||
),
|
||||
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandUnfollow,
|
||||
executor.CommandSummaryLookup(executor.CommandUnfollow),
|
||||
),
|
||||
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandUnblock,
|
||||
executor.CommandSummaryLookup(executor.CommandUnblock),
|
||||
),
|
||||
executor.CommandShow: executor.NewShowExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandShow,
|
||||
executor.CommandSummaryLookup(executor.CommandShow),
|
||||
),
|
||||
executor.CommandVersion: executor.NewVersionExecutor(
|
||||
enbasPrinter,
|
||||
executor.CommandVersion,
|
||||
executor.CommandSummaryLookup(executor.CommandVersion),
|
||||
binaryVersion,
|
||||
|
@ -167,7 +187,8 @@ func run() error {
|
|||
gitCommit,
|
||||
),
|
||||
executor.CommandWhoami: executor.NewWhoAmIExecutor(
|
||||
topLevelFlags,
|
||||
enbasPrinter,
|
||||
topLevelFlags.ConfigDir,
|
||||
executor.CommandWhoami,
|
||||
executor.CommandSummaryLookup(executor.CommandWhoami),
|
||||
),
|
||||
|
|
|
@ -17,7 +17,7 @@ const (
|
|||
listPath string = "/api/v1/lists"
|
||||
)
|
||||
|
||||
func (g *Client) GetAllLists() (model.Lists, error) {
|
||||
func (g *Client) GetAllLists() ([]model.List, error) {
|
||||
url := g.Authentication.Instance + listPath
|
||||
|
||||
var lists []model.List
|
||||
|
|
|
@ -9,22 +9,25 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type AcceptOrRejectExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
accountName string
|
||||
command string
|
||||
}
|
||||
|
||||
func NewAcceptOrRejectExecutor(tlf TopLevelFlags, name, summary string) *AcceptOrRejectExecutor {
|
||||
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, configDir, name, summary string) *AcceptOrRejectExecutor {
|
||||
acceptExe := AcceptOrRejectExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
topLevelFlags: tlf,
|
||||
printer: enbasPrinter,
|
||||
configDir: configDir,
|
||||
command: name,
|
||||
}
|
||||
|
||||
|
@ -46,7 +49,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: a.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountName, a.topLevelFlags.ConfigDir)
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully accepted the follow request.")
|
||||
a.printer.PrintSuccess("Successfully accepted the follow request.")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully rejected the follow request.")
|
||||
a.printer.PrintSuccess("Successfully rejected the follow request.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,12 +10,14 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type AddExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
toResourceType string
|
||||
listID string
|
||||
|
@ -26,13 +28,15 @@ type AddExecutor struct {
|
|||
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)
|
||||
|
||||
addExe := AddExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
accountNames: MultiStringFlagValue(emptyArr),
|
||||
topLevelFlags: tlf,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(a.configDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
|
||||
}
|
||||
|
@ -105,7 +109,16 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
|
|||
for ind := range a.accountNames {
|
||||
accountID, err := getTheirAccountID(gtsClient, a.accountNames[ind])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get the account ID for %s, %w", a.accountNames[ind], err)
|
||||
return fmt.Errorf("unable to get the account ID for %s: %w", a.accountNames[ind], err)
|
||||
}
|
||||
|
||||
relationship, err := gtsClient.GetAccountRelationship(accountID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get your relationship to %s: %w", a.accountNames[ind], err)
|
||||
}
|
||||
|
||||
if !relationship.Following {
|
||||
return NotFollowingError{Account: a.accountNames[ind]}
|
||||
}
|
||||
|
||||
accountIDs[ind] = accountID
|
||||
|
@ -115,7 +128,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
|
|||
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
|
||||
}
|
||||
|
@ -141,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))
|
||||
}
|
||||
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.topLevelFlags.ConfigDir)
|
||||
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
@ -157,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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully added the private note to the account.")
|
||||
a.printer.PrintSuccess("Successfully added the private note to the account.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -187,7 +200,7 @@ func (a *AddExecutor) addStatusToBookmarks(gtsClient *client.Client) error {
|
|||
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
|
||||
}
|
||||
|
@ -219,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)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully added a %s to the status.\n", a.resourceType)
|
||||
a.printer.PrintSuccess("Successfully added a " + a.resourceType + " to the status.\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -229,7 +242,7 @@ func (a *AddExecutor) addBoostToStatus(gtsClient *client.Client) error {
|
|||
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
|
||||
}
|
||||
|
@ -276,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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully added your vote(s) to the poll.")
|
||||
a.printer.PrintSuccess("Successfully added your vote(s) to the poll.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,22 +9,25 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type BlockOrUnblockExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
accountName string
|
||||
command string
|
||||
}
|
||||
|
||||
func NewBlockOrUnblockExecutor(tlf TopLevelFlags, name, summary string) *BlockOrUnblockExecutor {
|
||||
func NewBlockOrUnblockExecutor(printer *printer.Printer, configDir, name, summary string) *BlockOrUnblockExecutor {
|
||||
blockExe := BlockOrUnblockExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
topLevelFlags: tlf,
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
command: name,
|
||||
}
|
||||
|
||||
|
@ -46,7 +49,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: b.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(b.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(b.configDir)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.topLevelFlags.ConfigDir)
|
||||
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully blocked the account.")
|
||||
b.printer.PrintSuccess("Successfully blocked the account.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -85,7 +88,7 @@ func (b *BlockOrUnblockExecutor) unblockAccount(gtsClient *client.Client, accoun
|
|||
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
|
||||
}
|
||||
|
|
|
@ -11,13 +11,14 @@ import (
|
|||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
type CreateExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
addPoll bool
|
||||
boostable bool
|
||||
federated bool
|
||||
|
@ -26,6 +27,7 @@ type CreateExecutor struct {
|
|||
pollHidesVoteCounts bool
|
||||
replyable bool
|
||||
sensitive *bool
|
||||
configDir string
|
||||
content string
|
||||
contentType string
|
||||
fromFile string
|
||||
|
@ -39,11 +41,12 @@ type CreateExecutor struct {
|
|||
pollOptions MultiStringFlagValue
|
||||
}
|
||||
|
||||
func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor {
|
||||
func NewCreateExecutor(printer *printer.Printer, configDir, name, summary string) *CreateExecutor {
|
||||
createExe := CreateExecutor{
|
||||
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")
|
||||
|
@ -87,7 +90,7 @@ func (c *CreateExecutor) Execute() error {
|
|||
return FlagNotSetError{flagText: flagType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(c.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully created the following list:")
|
||||
utilities.Display(list, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
|
||||
c.printer.PrintSuccess("Successfully created the following list:")
|
||||
c.printer.PrintList(list)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -217,13 +220,13 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
|||
form.Poll = &poll
|
||||
}
|
||||
|
||||
status, err := gtsClient.CreateStatus(form)
|
||||
_, err = gtsClient.CreateStatus(form)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the status: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully created the following status:")
|
||||
utilities.Display(status, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
|
||||
c.printer.PrintSuccess("Successfully created the following status:")
|
||||
//utilities.Display(status, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,20 +9,24 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type DeleteExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
listID string
|
||||
}
|
||||
|
||||
func NewDeleteExecutor(tlf TopLevelFlags, name, summary string) *DeleteExecutor {
|
||||
func NewDeleteExecutor(printer *printer.Printer, configDir, name, summary string) *DeleteExecutor {
|
||||
deleteExe := DeleteExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
topLevelFlags: tlf,
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(d.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(d.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("The list was successfully deleted.")
|
||||
d.printer.PrintSuccess("The list was successfully deleted.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,23 +10,26 @@ import (
|
|||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"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 {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
listID string
|
||||
listTitle string
|
||||
listRepliesPolicy string
|
||||
}
|
||||
|
||||
func NewEditExecutor(tlf TopLevelFlags, name, summary string) *EditExecutor {
|
||||
func NewEditExecutor(printer *printer.Printer, configDir, name, summary string) *EditExecutor {
|
||||
editExe := EditExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
topLevelFlags: tlf,
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(e.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(e.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully updated the list.")
|
||||
utilities.Display(updatedList, *e.topLevelFlags.NoColor, e.topLevelFlags.Pager)
|
||||
e.printer.PrintSuccess("Successfully updated the list.")
|
||||
e.printer.PrintList(updatedList)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -94,3 +94,11 @@ func (e NoPollOptionError) Error() string {
|
|||
flagPollOption +
|
||||
" flag to add options to the poll"
|
||||
}
|
||||
|
||||
type NotFollowingError struct {
|
||||
Account string
|
||||
}
|
||||
|
||||
func (e NotFollowingError) Error() string {
|
||||
return "you are not following " + e.Account
|
||||
}
|
||||
|
|
|
@ -9,12 +9,14 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type FollowOrUnfollowExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
printer *printer.Printer
|
||||
configDir string
|
||||
resourceType string
|
||||
accountName string
|
||||
showReposts bool
|
||||
|
@ -22,11 +24,12 @@ type FollowOrUnfollowExecutor struct {
|
|||
action string
|
||||
}
|
||||
|
||||
func NewFollowOrUnfollowExecutor(tlf TopLevelFlags, name, summary string) *FollowOrUnfollowExecutor {
|
||||
func NewFollowOrUnfollowExecutor(printer *printer.Printer, configDir, name, summary string) *FollowOrUnfollowExecutor {
|
||||
command := FollowOrUnfollowExecutor{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
topLevelFlags: tlf,
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
action: name,
|
||||
}
|
||||
|
||||
|
@ -50,7 +53,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: f.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(f.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(f.configDir)
|
||||
if err != nil {
|
||||
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 {
|
||||
accountID, err := getAccountID(gtsClient, false, f.accountName, f.topLevelFlags.ConfigDir)
|
||||
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
fmt.Println("The follow request was sent successfully.")
|
||||
f.printer.PrintSuccess("Successfully sent the follow request.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -95,7 +98,7 @@ func (f *FollowOrUnfollowExecutor) unfollowAccount(gtsClient *client.Client, acc
|
|||
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
|
||||
}
|
||||
|
|
|
@ -10,16 +10,19 @@ import (
|
|||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
type ShowExecutor struct {
|
||||
*flag.FlagSet
|
||||
topLevelFlags TopLevelFlags
|
||||
|
||||
printer *printer.Printer
|
||||
myAccount bool
|
||||
skipAccountRelationship bool
|
||||
showUserPreferences bool
|
||||
showInBrowser bool
|
||||
configDir string
|
||||
resourceType string
|
||||
accountName string
|
||||
statusID string
|
||||
|
@ -30,10 +33,12 @@ type ShowExecutor struct {
|
|||
limit int
|
||||
}
|
||||
|
||||
func NewShowExecutor(tlf TopLevelFlags, name, summary string) *ShowExecutor {
|
||||
func NewShowExecutor(printer *printer.Printer, configDir, name, summary string) *ShowExecutor {
|
||||
showExe := ShowExecutor{
|
||||
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")
|
||||
|
@ -80,7 +85,7 @@ func (s *ShowExecutor) Execute() error {
|
|||
return UnsupportedTypeError{resourceType: s.resourceType}
|
||||
}
|
||||
|
||||
gtsClient, err := client.NewClientFromConfig(s.topLevelFlags.ConfigDir)
|
||||
gtsClient, err := client.NewClientFromConfig(s.configDir)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
utilities.Display(instance, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
utilities.Display(instance, false, "")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -106,7 +111,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
|||
)
|
||||
|
||||
if s.myAccount {
|
||||
account, err = getMyAccount(gtsClient, s.topLevelFlags.ConfigDir)
|
||||
account, err = getMyAccount(gtsClient, s.configDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("received an error while getting the account details: %w", err)
|
||||
}
|
||||
|
@ -127,7 +132,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
utilities.Display(account, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccount(account)
|
||||
|
||||
if !s.myAccount && !s.skipAccountRelationship {
|
||||
relationship, err := gtsClient.GetAccountRelationship(account.ID)
|
||||
|
@ -135,7 +140,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
|||
return fmt.Errorf("unable to retrieve the relationship to this account: %w", err)
|
||||
}
|
||||
|
||||
utilities.Display(relationship, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccountRelationship(relationship)
|
||||
}
|
||||
|
||||
if s.myAccount && s.showUserPreferences {
|
||||
|
@ -144,7 +149,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
|
|||
return fmt.Errorf("unable to retrieve the user preferences: %w", err)
|
||||
}
|
||||
|
||||
utilities.Display(preferences, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
utilities.Display(preferences, false, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -166,7 +171,7 @@ func (s *ShowExecutor) showStatus(gtsClient *client.Client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
utilities.Display(status, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintStatus(status)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -210,12 +215,12 @@ func (s *ShowExecutor) showTimeline(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
utilities.Display(timeline, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintStatusList(timeline)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -244,7 +249,7 @@ func (s *ShowExecutor) showList(gtsClient *client.Client) error {
|
|||
list.Accounts = accountMap
|
||||
}
|
||||
|
||||
utilities.Display(list, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintList(list)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -256,18 +261,18 @@ func (s *ShowExecutor) showLists(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(lists) == 0 {
|
||||
fmt.Println("You have no lists.")
|
||||
s.printer.PrintInfo("You have no lists.\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
utilities.Display(lists, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintLists(lists)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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 {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
@ -278,16 +283,16 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(followers.Accounts) > 0 {
|
||||
utilities.Display(followers, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccountList(followers)
|
||||
} 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
|
||||
}
|
||||
|
||||
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 {
|
||||
return fmt.Errorf("received an error while getting the account ID: %w", err)
|
||||
}
|
||||
|
@ -298,9 +303,9 @@ func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(following.Accounts) > 0 {
|
||||
utilities.Display(following, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccountList(following)
|
||||
} 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
|
||||
|
@ -313,9 +318,9 @@ func (s *ShowExecutor) showBlocked(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(blocked.Accounts) > 0 {
|
||||
utilities.Display(blocked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccountList(blocked)
|
||||
} else {
|
||||
fmt.Println("You have no blocked accounts.")
|
||||
s.printer.PrintInfo("You have no blocked accounts.\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -328,9 +333,9 @@ func (s *ShowExecutor) showBookmarks(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(bookmarks.Statuses) > 0 {
|
||||
utilities.Display(bookmarks, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintStatusList(bookmarks)
|
||||
} else {
|
||||
fmt.Println("You have no bookmarks.")
|
||||
s.printer.PrintInfo("You have no bookmarks.\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -343,9 +348,9 @@ func (s *ShowExecutor) showLiked(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(liked.Statuses) > 0 {
|
||||
utilities.Display(liked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintStatusList(liked)
|
||||
} else {
|
||||
fmt.Printf("You have no %s statuses.\n", s.resourceType)
|
||||
s.printer.PrintInfo("You have no " + s.resourceType + " statuses.\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -358,9 +363,9 @@ func (s *ShowExecutor) showFollowRequests(gtsClient *client.Client) error {
|
|||
}
|
||||
|
||||
if len(accounts.Accounts) > 0 {
|
||||
utilities.Display(accounts, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
s.printer.PrintAccountList(accounts)
|
||||
} else {
|
||||
fmt.Println("You have no follow requests.")
|
||||
s.printer.PrintInfo("You have no follow requests.\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -376,7 +381,7 @@ func (s *ShowExecutor) showPoll(gtsClient *client.Client) error {
|
|||
return fmt.Errorf("unable to retrieve the poll: %w", err)
|
||||
}
|
||||
|
||||
utilities.Display(poll, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
|
||||
utilities.Display(poll, false, "")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,20 +9,23 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type SwitchExecutor struct {
|
||||
*flag.FlagSet
|
||||
|
||||
topLevelFlags TopLevelFlags
|
||||
configDir string
|
||||
toResourceType 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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
topLevelFlags: tlf,
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
}
|
||||
|
||||
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
|
||||
|
@ -51,11 +54,11 @@ func (s *SwitchExecutor) switchToAccount() error {
|
|||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ package executor
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type VersionExecutor struct {
|
||||
*flag.FlagSet
|
||||
printer *printer.Printer
|
||||
showFullVersion bool
|
||||
binaryVersion string
|
||||
buildTime string
|
||||
|
@ -20,9 +20,19 @@ type VersionExecutor struct {
|
|||
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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
|
||||
printer: enbasPrinter,
|
||||
binaryVersion: binaryVersion,
|
||||
buildTime: buildTime,
|
||||
goVersion: goVersion,
|
||||
|
@ -38,24 +48,7 @@ func NewVersionExecutor(name, summary, binaryVersion, buildTime, goVersion, gitC
|
|||
}
|
||||
|
||||
func (v *VersionExecutor) Execute() error {
|
||||
var builder strings.Builder
|
||||
|
||||
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())
|
||||
v.printer.PrintVersion(v.showFullVersion, v.binaryVersion, v.buildTime, v.goVersion, v.gitCommit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,18 +9,22 @@ import (
|
|||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
|
||||
)
|
||||
|
||||
type WhoAmIExecutor struct {
|
||||
*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{
|
||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||
topLevelFlags: tlf,
|
||||
|
||||
printer: printer,
|
||||
configDir: configDir,
|
||||
}
|
||||
|
||||
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
|
||||
|
@ -29,12 +33,12 @@ func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor
|
|||
}
|
||||
|
||||
func (c *WhoAmIExecutor) Execute() error {
|
||||
config, err := config.NewCredentialsConfigFromFile(c.topLevelFlags.ConfigDir)
|
||||
config, err := config.NewCredentialsConfigFromFile(c.configDir)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
|
@ -63,59 +60,6 @@ type Field struct {
|
|||
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 {
|
||||
ID string `json:"id"`
|
||||
PrivateNote string `json:"note"`
|
||||
|
@ -133,53 +77,6 @@ type AccountRelationship struct {
|
|||
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
|
||||
|
||||
const (
|
||||
|
@ -193,36 +90,3 @@ type AccountList struct {
|
|||
Type AccountListType
|
||||
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
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ package model
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
type ListRepliesPolicy int
|
||||
|
@ -107,53 +105,3 @@ type List struct {
|
|||
Title string `json:"title"`
|
||||
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,11 +5,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
|
@ -139,86 +135,7 @@ type MediaDimensions struct {
|
|||
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 {
|
||||
Name string
|
||||
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()
|
||||
}
|
||||
|
|
108
internal/printer/account.go
Normal file
108
internal/printer/account.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
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) {
|
||||
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 + "\n")
|
||||
|
||||
printToStdout(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")
|
||||
|
||||
printToStdout(builder.String())
|
||||
}
|
||||
|
||||
func (p Printer) PrintAccountRelationship(relationship model.AccountRelationship) {
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString("\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))
|
||||
}
|
||||
|
||||
builder.WriteString("\n\n")
|
||||
|
||||
printToStdout(builder.String())
|
||||
}
|
45
internal/printer/list.go
Normal file
45
internal/printer/list.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
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())
|
||||
}
|
62
internal/printer/poll.go
Normal file
62
internal/printer/poll.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package printer
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
||||
)
|
||||
|
||||
func (p Printer) pollContent(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:") + " " + utilities.FormatTime(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
|
||||
}
|
168
internal/printer/printer.go
Normal file
168
internal/printer/printer.go
Normal file
|
@ -0,0 +1,168 @@
|
|||
// 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"
|
||||
)
|
||||
|
||||
type theme struct {
|
||||
reset string
|
||||
boldblue string
|
||||
boldmagenta string
|
||||
green string
|
||||
boldgreen string
|
||||
grey 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",
|
||||
}
|
||||
|
||||
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.green + p.successSymbol + p.theme.reset
|
||||
if p.noColor {
|
||||
success = p.successSymbol
|
||||
}
|
||||
|
||||
printToStdout(success + " " + text + "\n")
|
||||
}
|
||||
|
||||
func (p Printer) PrintFailure(text string) {
|
||||
printToStderr(p.failureSymbol + " " + text)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
93
internal/printer/status.go
Normal file
93
internal/printer/status.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
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.pollContent(*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.pollContent(*status.Poll))
|
||||
}
|
||||
|
||||
builder.WriteString(
|
||||
"\n\n" +
|
||||
p.fieldFormat("Status ID:") + " " + statusID + "\t" +
|
||||
p.fieldFormat("Created at:") + " " + utilities.FormatTime(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())
|
||||
}
|
Loading…
Reference in a new issue