Compare commits

..

3 commits

Author SHA1 Message Date
81f5b527a0
add line wrapping support 2024-02-23 09:34:52 +00:00
db6017dccf
parse timestamp fields into time.Time 2024-02-23 08:36:58 +00:00
4cbf1d4b4d
refactor: some code refactoring
- moved the usage functions to usage.go
- removed duplicate definitions of oauth2Conf
2024-02-23 07:49:02 +00:00
6 changed files with 132 additions and 106 deletions

View file

@ -76,7 +76,18 @@ func (c *loginCommand) Execute() error {
return fmt.Errorf("unable to register the application; %w", err) return fmt.Errorf("unable to register the application; %w", err)
} }
consentPageURL := authCodeURL(gtsClient.Authentication) oauth2Conf := oauth2.Config{
ClientID: gtsClient.Authentication.ClientID,
ClientSecret: gtsClient.Authentication.ClientSecret,
Scopes: []string{"read"},
RedirectURL: internal.RedirectUri,
Endpoint: oauth2.Endpoint{
AuthURL: gtsClient.Authentication.Instance + "/oauth/authorize",
TokenURL: gtsClient.Authentication.Instance + "/oauth/token",
},
}
consentPageURL := authCodeURL(oauth2Conf)
openLink(consentPageURL) openLink(consentPageURL)
@ -89,7 +100,7 @@ func (c *loginCommand) Execute() error {
return fmt.Errorf("failed to read access code; %w", err) return fmt.Errorf("failed to read access code; %w", err)
} }
gtsClient.Authentication, err = addAccessToken(gtsClient.Authentication, code) gtsClient.Authentication, err = addAccessToken(gtsClient.Authentication, oauth2Conf, code)
if err != nil { if err != nil {
return fmt.Errorf("unable to get the access token; %w", err) return fmt.Errorf("unable to get the access token; %w", err)
} }
@ -109,36 +120,17 @@ func (c *loginCommand) Execute() error {
return nil return nil
} }
func authCodeURL(account config.Authentication) string { func authCodeURL(oauth2Conf oauth2.Config) string {
config := oauth2.Config{ url := oauth2Conf.AuthCodeURL(
ClientID: account.ClientID, "state",
ClientSecret: account.ClientSecret, oauth2.AccessTypeOffline,
Scopes: []string{"read"}, ) + "&client_name=" + internal.ApplicationName
RedirectURL: internal.RedirectUri,
Endpoint: oauth2.Endpoint{
AuthURL: account.Instance + "/oauth/authorize",
TokenURL: account.Instance + "/oauth/token",
},
}
url := config.AuthCodeURL("state", oauth2.AccessTypeOffline) + fmt.Sprintf("&client_name=%s", internal.ApplicationName)
return url return url
} }
func addAccessToken(authentication config.Authentication, code string) (config.Authentication, error) { func addAccessToken(authentication config.Authentication, oauth2Conf oauth2.Config, code string) (config.Authentication, error) {
ouauth2Conf := oauth2.Config{ token, err := oauth2Conf.Exchange(context.Background(), code)
ClientID: authentication.ClientID,
ClientSecret: authentication.ClientSecret,
Scopes: []string{"read", "write"},
RedirectURL: internal.RedirectUri,
Endpoint: oauth2.Endpoint{
AuthURL: authentication.Instance + "/oauth/authorize",
TokenURL: authentication.Instance + "/oauth/token",
},
}
token, err := ouauth2Conf.Exchange(context.Background(), code)
if err != nil { if err != nil {
return config.Authentication{}, fmt.Errorf("unable to exchange the code for an access token; %w", err) return config.Authentication{}, fmt.Errorf("unable to exchange the code for an access token; %w", err)
} }

View file

@ -4,8 +4,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"slices"
"strings"
) )
type Executor interface { type Executor interface {
@ -75,71 +73,3 @@ func run() error {
return nil return nil
} }
func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
return func() {
var builder strings.Builder
fmt.Fprintf(
&builder,
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
name,
summary,
name,
)
flagset.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(
&builder,
"\n -%s, --%s\n %s",
f.Name,
f.Name,
f.Usage,
)
})
builder.WriteString("\n")
w := flag.CommandLine.Output()
fmt.Fprint(w, builder.String())
}
}
func enbasUsageFunc(summaries map[string]string) func() {
cmds := make([]string, len(summaries))
ind := 0
for k := range summaries {
cmds[ind] = k
ind++
}
slices.Sort(cmds)
return func() {
var builder strings.Builder
builder.WriteString("SUMMARY:\n enbas - A GoToSocial client for the terminal.\n\n")
if binaryVersion != "" {
builder.WriteString("VERSION:\n " + binaryVersion + "\n\n")
}
builder.WriteString("USAGE:\n enbas [flags]\n enbas [command]\n\nCOMMANDS:")
for _, cmd := range cmds {
fmt.Fprintf(&builder, "\n %s\t%s", cmd, summaries[cmd])
}
builder.WriteString("\n\nFLAGS:\n -help, --help\n print the help message\n")
flag.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(&builder, "\n -%s, --%s\n %s\n", f.Name, f.Name, f.Usage)
})
builder.WriteString("\nUse \"enbas [command] --help\" for more information about a command.\n")
w := flag.CommandLine.Output()
fmt.Fprint(w, builder.String())
}
}

View file

@ -5,6 +5,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"strings" "strings"
"unicode"
"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"
@ -32,7 +33,7 @@ var accountDetailsFormat = `
ACCOUNT ID: ACCOUNT ID:
%s %s
CREATED AT: JOINED ON:
%s %s
STATS: STATS:
@ -144,11 +145,11 @@ func (c *showCommand) showAccount(gts *client.Client) error {
account.DisplayName, account.DisplayName,
account.Username, account.Username,
account.ID, account.ID,
account.CreatedAt, account.CreatedAt.Format("02 Jan 2006"),
account.FollowersCount, account.FollowersCount,
account.FollowingCount, account.FollowingCount,
account.StatusCount, account.StatusCount,
stripHTMLTags(account.Note), wrapLine(stripHTMLTags(account.Note), "\n ", 80),
metadata, metadata,
account.URL, account.URL,
) )
@ -171,3 +172,26 @@ func stripHTMLTags(text string) string {
} }
} }
} }
func wrapLine(line, separator string, charLimit int) string {
if len(line) <= charLimit {
return line
}
leftcursor, rightcursor := 0, 0
var builder strings.Builder
for rightcursor < (len(line) - charLimit) {
rightcursor += charLimit
for !unicode.IsSpace(rune(line[rightcursor-1])) {
rightcursor--
}
builder.WriteString(line[leftcursor:rightcursor] + separator)
leftcursor = rightcursor
}
builder.WriteString(line[rightcursor:])
return builder.String()
}

76
cmd/enbas/usage.go Normal file
View file

@ -0,0 +1,76 @@
package main
import (
"flag"
"fmt"
"slices"
"strings"
)
func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
return func() {
var builder strings.Builder
fmt.Fprintf(
&builder,
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
name,
summary,
name,
)
flagset.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(
&builder,
"\n -%s, --%s\n %s",
f.Name,
f.Name,
f.Usage,
)
})
builder.WriteString("\n")
w := flag.CommandLine.Output()
fmt.Fprint(w, builder.String())
}
}
func enbasUsageFunc(summaries map[string]string) func() {
cmds := make([]string, len(summaries))
ind := 0
for k := range summaries {
cmds[ind] = k
ind++
}
slices.Sort(cmds)
return func() {
var builder strings.Builder
builder.WriteString("SUMMARY:\n enbas - A GoToSocial client for the terminal.\n\n")
if binaryVersion != "" {
builder.WriteString("VERSION:\n " + binaryVersion + "\n\n")
}
builder.WriteString("USAGE:\n enbas [flags]\n enbas [command]\n\nCOMMANDS:")
for _, cmd := range cmds {
fmt.Fprintf(&builder, "\n %s\t%s", cmd, summaries[cmd])
}
builder.WriteString("\n\nFLAGS:\n -help, --help\n print the help message\n")
flag.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(&builder, "\n -%s, --%s\n %s\n", f.Name, f.Name, f.Usage)
})
builder.WriteString("\nUse \"enbas [command] --help\" for more information about a command.\n")
w := flag.CommandLine.Output()
fmt.Fprint(w, builder.String())
}
}

View file

@ -1,11 +1,13 @@
package model package model
import "time"
type Account struct { type Account struct {
Acct string `json:"acct"` Acct string `json:"acct"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
AvatarStatic string `json:"avatar_static"` AvatarStatic string `json:"avatar_static"`
Bot bool `json:"bot"` Bot bool `json:"bot"`
CreatedAt string `json:"created_at"` CreatedAt time.Time `json:"created_at"`
CustomCSS string `json:"custom_css"` CustomCSS string `json:"custom_css"`
Discoverable bool `json:"discoverable"` Discoverable bool `json:"discoverable"`
DisplayName string `json:"display_name"` DisplayName string `json:"display_name"`
@ -19,7 +21,7 @@ type Account struct {
ID string `json:"id"` ID string `json:"id"`
LastStatusAt string `json:"last_status_at"` LastStatusAt string `json:"last_status_at"`
Locked bool `json:"locked"` Locked bool `json:"locked"`
MuteExpiresAt string `json:"mute_expires_at"` MuteExpiresAt time.Time `json:"mute_expires_at"`
Note string `json:"note"` Note string `json:"note"`
Role AccountRole `json:"role"` Role AccountRole `json:"role"`
Source Source `json:"source"` Source Source `json:"source"`

View file

@ -1,12 +1,14 @@
package model package model
import "time"
type Status struct { type Status struct {
Account Account `json:"account"` Account Account `json:"account"`
Application Application `json:"application"` Application Application `json:"application"`
Bookmarked bool `json:"bookmarked"` Bookmarked bool `json:"bookmarked"`
Card Card `json:"card"` Card Card `json:"card"`
Content string `json:"content"` Content string `json:"content"`
CreatedAt string `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Emojis []Emoji `json:"emojis"` Emojis []Emoji `json:"emojis"`
Favourited bool `json:"favourited"` Favourited bool `json:"favourited"`
FavouritesCount int `json:"favourites_count"` FavouritesCount int `json:"favourites_count"`
@ -61,7 +63,7 @@ type Poll struct {
Expired bool `json:"expired"` Expired bool `json:"expired"`
Voted bool `json:"voted"` Voted bool `json:"voted"`
Multiple bool `json:"multiple"` Multiple bool `json:"multiple"`
ExpiredAt string `json:"expires_at"` ExpiredAt time.Time `json:"expires_at"`
ID string `json:"id"` ID string `json:"id"`
OwnVotes []int `json:"own_votes"` OwnVotes []int `json:"own_votes"`
VotersCount int `json:"voters_count"` VotersCount int `json:"voters_count"`
@ -80,7 +82,7 @@ type StatusReblogged struct {
Bookmarked bool `json:"bookmarked"` Bookmarked bool `json:"bookmarked"`
Card Card `json:"card"` Card Card `json:"card"`
Content string `json:"content"` Content string `json:"content"`
CreatedAt string `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Emojis []Emoji `json:"emojis"` Emojis []Emoji `json:"emojis"`
Favourited bool `json:"favourited"` Favourited bool `json:"favourited"`
FavouritesCount int `json:"favourites_count"` FavouritesCount int `json:"favourites_count"`