Update to handle non-int64 IDs
Pleroma/Akkoma and GotoSocial use opaque IDs rather than `int64`s like
Mastodon which means that `madon` can't talk to either of those.
This commit updates everything that can be an ID to `madon.ActivityID`
which is an alias for `string` - can't create a specific type for it
since there's more than a few places where they're concatenated directly
to strings for URLs, etc. Which means it could just as easily be a
direct `string` type itself but I find that having distinct types can
often make the code more readable and understandable.
One extra bit is that `statusOpts` has grown a `_hasReplyTo` boolean
to indicate whether the `--in-reply-to` flag was given or not because
we can't distinguish because "empty because default" or "empty because
given and empty". Another way around this would be to set the default
to some theoretically impossible or unlikely string but you never
know when someone might spin up an instance where, e.g., admin posts
have negative integer IDs.
--- a/cmd/accounts.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/accounts.go Mon Jan 23 16:39:02 2023 +0000
@@ -20,30 +20,30 @@
var accountUpdateFlags, accountMuteFlags, accountFollowFlags *flag.FlagSet
var accountsOpts struct {
- accountID int64
+ accountID madon.ActivityID
accountUID string
- unset bool // TODO remove eventually?
- limit, keep uint // Limit the results
- sinceID, maxID int64 // Query boundaries
- all bool // Try to fetch all results
- onlyMedia, onlyPinned bool // For acccount statuses
- excludeReplies bool // For acccount statuses
- remoteUID string // For account follow
- reblogs bool // For account follow
- acceptFR, rejectFR bool // For account follow_requests
- list bool // For account follow_requests/reports
- accountIDs string // For account relationships
- statusIDs string // For account reports
- comment string // For account reports
- displayName, note string // For account update
- profileFields []string // For account update
- avatar, header string // For account update
- defaultLanguage string // For account update
- defaultPrivacy string // For account update
- defaultSensitive bool // For account update
- locked, bot bool // For account update
- muteNotifications bool // For account mute
- following bool // For account search
+ unset bool // TODO remove eventually?
+ limit, keep uint // Limit the results
+ sinceID, maxID madon.ActivityID // Query boundaries
+ all bool // Try to fetch all results
+ onlyMedia, onlyPinned bool // For acccount statuses
+ excludeReplies bool // For acccount statuses
+ remoteUID string // For account follow
+ reblogs bool // For account follow
+ acceptFR, rejectFR bool // For account follow_requests
+ list bool // For account follow_requests/reports
+ accountIDs string // For account relationships
+ statusIDs string // For account reports
+ comment string // For account reports
+ displayName, note string // For account update
+ profileFields []string // For account update
+ avatar, header string // For account update
+ defaultLanguage string // For account update
+ defaultPrivacy string // For account update
+ defaultSensitive bool // For account update
+ locked, bot bool // For account update
+ muteNotifications bool // For account mute
+ following bool // For account search
}
func init() {
@@ -53,12 +53,12 @@
accountsCmd.AddCommand(accountSubcommands...)
// Global flags
- accountsCmd.PersistentFlags().Int64VarP(&accountsOpts.accountID, "account-id", "a", 0, "Account ID number")
+ accountsCmd.PersistentFlags().StringVarP(&accountsOpts.accountID, "account-id", "a", "", "Account ID number")
accountsCmd.PersistentFlags().StringVarP(&accountsOpts.accountUID, "user-id", "u", "", "Account user ID")
accountsCmd.PersistentFlags().UintVarP(&accountsOpts.limit, "limit", "l", 0, "Limit number of API results")
accountsCmd.PersistentFlags().UintVarP(&accountsOpts.keep, "keep", "k", 0, "Limit number of results")
- accountsCmd.PersistentFlags().Int64Var(&accountsOpts.sinceID, "since-id", 0, "Request IDs greater than a value")
- accountsCmd.PersistentFlags().Int64Var(&accountsOpts.maxID, "max-id", 0, "Request IDs less (or equal) than a value")
+ accountsCmd.PersistentFlags().StringVar(&accountsOpts.sinceID, "since-id", "", "Request IDs greater than a value")
+ accountsCmd.PersistentFlags().StringVar(&accountsOpts.maxID, "max-id", "", "Request IDs less (or equal) than a value")
accountsCmd.PersistentFlags().BoolVar(&accountsOpts.all, "all", false, "Fetch all results")
// Subcommand flags
@@ -377,7 +377,7 @@
// Check account is provided in only one way
aCounter := 0
- if opt.accountID > 0 {
+ if opt.accountID != "" {
aCounter++
}
if opt.accountUID != "" {
@@ -396,8 +396,8 @@
if userInArg {
// Is the argument an account ID?
- if n, err := strconv.ParseInt(args[0], 10, 64); err == nil {
- opt.accountID = n
+ if _, err := strconv.ParseInt(args[0], 10, 64); err == nil {
+ opt.accountID = args[0]
} else if strings.HasPrefix(args[0], "https://") || strings.HasPrefix(args[0], "http://") {
// That is not a remote UID scheme
opt.accountUID = args[0]
@@ -417,7 +417,7 @@
}
if opt.accountUID != "" {
- if opt.accountID > 0 {
+ if opt.accountID != "" {
return errors.New("cannot use both account ID and UID")
}
// Sign in early to look the user id up
@@ -426,7 +426,7 @@
return err
}
opt.accountID, err = accountLookupUser(opt.accountUID)
- if err != nil || opt.accountID < 1 {
+ if err != nil || opt.accountID == "" {
if err != nil {
errPrint("Cannot find user '%s': %v", opt.accountUID, err)
} else {
@@ -441,18 +441,18 @@
// These subcommands do not require an account ID
case "favourites", "blocks", "mutes", "pinned":
// Those subcommands can not use an account ID
- if opt.accountID > 0 {
+ if opt.accountID != "" {
return errors.New("useless account ID")
}
case "follow", "unfollow":
// We need an account ID or a remote UID
- if opt.accountID < 1 && opt.remoteUID == "" {
+ if opt.accountID == "" && opt.remoteUID == "" {
return errors.New("missing account ID or URI")
}
- if opt.accountID > 0 && opt.remoteUID != "" {
+ if opt.accountID != "" && opt.remoteUID != "" {
return errors.New("cannot use both account ID and URI")
}
- if (opt.unset || subcmd == "unfollow") && opt.accountID < 1 {
+ if (opt.unset || subcmd == "unfollow") && opt.accountID == "" {
return errors.New("unfollowing requires an account ID")
}
case "follow-requests":
@@ -468,27 +468,27 @@
if opt.acceptFR && opt.rejectFR {
return errors.New("incompatible options")
}
- if opt.accountID < 1 {
+ if opt.accountID == "" {
return errors.New("missing account ID")
}
}
case "relationships":
- if opt.accountID < 1 && len(opt.accountIDs) == 0 {
+ if opt.accountID == "" && len(opt.accountIDs) == 0 {
return errors.New("missing account IDs")
}
- if opt.accountID > 0 && len(opt.accountIDs) > 0 {
+ if opt.accountID != "" && len(opt.accountIDs) > 0 {
return errors.New("incompatible options")
}
case "reports":
if opt.list {
break // No argument needed
}
- if opt.accountID < 1 || len(opt.statusIDs) == 0 || opt.comment == "" {
+ if opt.accountID == "" || len(opt.statusIDs) == 0 || opt.comment == "" {
return errors.New("missing parameter")
}
case "followers", "following", "statuses":
// If the user's account ID is missing, get it
- if opt.accountID < 1 {
+ if opt.accountID == "" {
// Sign in now to look the user id up
if err := madonInit(true); err != nil {
return err
@@ -504,13 +504,13 @@
}
default:
// The other subcommands here require an account ID
- if opt.accountID < 1 {
+ if opt.accountID == "" {
return errors.New("missing account ID")
}
}
var limOpts *madon.LimitParams
- if opt.all || opt.limit > 0 || opt.sinceID > 0 || opt.maxID > 0 {
+ if opt.all || opt.limit > 0 || opt.sinceID != "" || opt.maxID != "" {
limOpts = new(madon.LimitParams)
limOpts.All = opt.all
}
@@ -518,10 +518,10 @@
if opt.limit > 0 {
limOpts.Limit = int(opt.limit)
}
- if opt.maxID > 0 {
+ if opt.maxID != "" {
limOpts.MaxID = opt.maxID
}
- if opt.sinceID > 0 {
+ if opt.sinceID != "" {
limOpts.SinceID = opt.sinceID
}
@@ -536,7 +536,7 @@
switch subcmd {
case "show":
var account *madon.Account
- if opt.accountID > 0 {
+ if opt.accountID != "" {
account, err = gClient.GetAccount(opt.accountID)
} else {
account, err = gClient.GetCurrentAccount()
@@ -574,7 +574,7 @@
obj = relationship
break
}
- if opt.accountID <= 0 {
+ if opt.accountID == "" {
if opt.remoteUID != "" {
// Remote account
var account *madon.Account
@@ -597,7 +597,7 @@
if opt.list {
var followRequests []madon.Account
followRequests, err = gClient.GetAccountFollowRequests(limOpts)
- if opt.accountID > 0 { // Display a specific request
+ if opt.accountID != "" { // Display a specific request
var fRequest *madon.Account
for _, fr := range followRequests {
if fr.ID == opt.accountID {
@@ -676,13 +676,13 @@
}
obj = accountList
case "relationships":
- var ids []int64
+ var ids []madon.ActivityID
ids, err = splitIDs(opt.accountIDs)
if err != nil {
return errors.New("cannot parse account IDs")
}
- if opt.accountID > 0 { // Allow --account-id
- ids = []int64{opt.accountID}
+ if opt.accountID != "" { // Allow --account-id
+ ids = []madon.ActivityID{opt.accountID}
}
if len(ids) < 1 {
return errors.New("missing account IDs")
@@ -701,7 +701,7 @@
break
}
// Send a report
- var ids []int64
+ var ids []madon.ActivityID
ids, err = splitIDs(opt.statusIDs)
if err != nil {
return errors.New("cannot parse status IDs")
@@ -807,17 +807,17 @@
// accountLookupUser tries to find a (single) user matching 'user'
// If the user is an HTTP URL, it will use the search API, else
// it will use the accounts/search API.
-func accountLookupUser(user string) (int64, error) {
- var accID int64
+func accountLookupUser(user string) (madon.ActivityID, error) {
+ var accID madon.ActivityID
if strings.HasPrefix(user, "https://") || strings.HasPrefix(user, "http://") {
res, err := gClient.Search(user, true)
if err != nil {
- return 0, err
+ return "", err
}
if res != nil {
if len(res.Accounts) > 1 {
- return 0, errors.New("several results")
+ return "", errors.New("several results")
}
if len(res.Accounts) == 1 {
accID = res.Accounts[0].ID
@@ -829,7 +829,7 @@
accList, err := gClient.SearchAccounts(user, false, &madon.LimitParams{Limit: 2})
if err != nil {
- return 0, err
+ return "", err
}
for _, u := range accList {
if u.Acct == user {
@@ -839,8 +839,8 @@
}
}
- if accID < 1 {
- return 0, errors.New("user not found")
+ if accID == "" {
+ return "", errors.New("user not found")
}
if verbose {
errPrint("User '%s' is account ID %d", user, user)
--- a/cmd/domainblocks.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/domainblocks.go Mon Jan 23 16:39:02 2023 +0000
@@ -17,9 +17,9 @@
var domainBlocksOpts struct {
show, block, unblock bool
- limit uint // Limit the results
- sinceID, maxID int64 // Query boundaries
- all bool // Try to fetch all results
+ limit uint // Limit the results
+ sinceID, maxID madon.ActivityID // Query boundaries
+ all bool // Try to fetch all results
}
// timelinesCmd represents the timelines command
@@ -41,8 +41,8 @@
domainBlocksCmd.Flags().BoolVar(&domainBlocksOpts.unblock, "unblock", false, "Unblock domain")
domainBlocksCmd.Flags().UintVarP(&domainBlocksOpts.limit, "limit", "l", 0, "Limit number of results")
- domainBlocksCmd.Flags().Int64Var(&domainBlocksOpts.sinceID, "since-id", 0, "Request IDs greater than a value")
- domainBlocksCmd.Flags().Int64Var(&domainBlocksOpts.maxID, "max-id", 0, "Request IDs less (or equal) than a value")
+ domainBlocksCmd.Flags().StringVar(&domainBlocksOpts.sinceID, "since-id", "", "Request IDs greater than a value")
+ domainBlocksCmd.Flags().StringVar(&domainBlocksOpts.maxID, "max-id", "", "Request IDs less (or equal) than a value")
domainBlocksCmd.Flags().BoolVar(&domainBlocksOpts.all, "all", false, "Fetch all results")
}
@@ -71,17 +71,17 @@
// Set up LimitParams
var limOpts *madon.LimitParams
- if opt.all || opt.limit > 0 || opt.sinceID > 0 || opt.maxID > 0 {
+ if opt.all || opt.limit > 0 || opt.sinceID != "" || opt.maxID != "" {
limOpts = new(madon.LimitParams)
limOpts.All = opt.all
}
if opt.limit > 0 {
limOpts.Limit = int(opt.limit)
}
- if opt.maxID > 0 {
+ if opt.maxID != "" {
limOpts.MaxID = opt.maxID
}
- if opt.sinceID > 0 {
+ if opt.sinceID != "" {
limOpts.SinceID = opt.sinceID
}
--- a/cmd/lists.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/lists.go Mon Jan 23 16:39:02 2023 +0000
@@ -15,8 +15,8 @@
)
var listsOpts struct {
- listID int64
- accountID int64
+ listID madon.ActivityID
+ accountID madon.ActivityID
accountIDs string
title string
@@ -51,20 +51,20 @@
listsCmd.PersistentFlags().UintVarP(&listsOpts.keep, "keep", "k", 0, "Limit number of results")
listsCmd.PersistentFlags().BoolVar(&listsOpts.all, "all", false, "Fetch all results")
- listsCmd.PersistentFlags().Int64VarP(&listsOpts.listID, "list-id", "G", 0, "List ID")
+ listsCmd.PersistentFlags().StringVarP(&listsOpts.listID, "list-id", "G", "", "List ID")
- listsGetSubcommand.Flags().Int64VarP(&listsOpts.accountID, "account-id", "a", 0, "Account ID number")
+ listsGetSubcommand.Flags().StringVarP(&listsOpts.accountID, "account-id", "a", "", "Account ID number")
// XXX accountUID?
- listsGetAccountsSubcommand.Flags().Int64VarP(&listsOpts.listID, "list-id", "G", 0, "List ID")
+ listsGetAccountsSubcommand.Flags().StringVarP(&listsOpts.listID, "list-id", "G", "", "List ID")
listsCreateSubcommand.Flags().StringVar(&listsOpts.title, "title", "", "List title")
listsUpdateSubcommand.Flags().StringVar(&listsOpts.title, "title", "", "List title")
listsAddAccountsSubcommand.Flags().StringVar(&listsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
- listsAddAccountsSubcommand.Flags().Int64VarP(&listsOpts.accountID, "account-id", "a", 0, "Account ID number")
+ listsAddAccountsSubcommand.Flags().StringVarP(&listsOpts.accountID, "account-id", "a", "", "Account ID number")
listsRemoveAccountsSubcommand.Flags().StringVar(&listsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
- listsRemoveAccountsSubcommand.Flags().Int64VarP(&listsOpts.accountID, "account-id", "a", 0, "Account ID number")
+ listsRemoveAccountsSubcommand.Flags().StringVarP(&listsOpts.accountID, "account-id", "a", "", "Account ID number")
}
var listsSubcommands = []*cobra.Command{
@@ -145,7 +145,7 @@
var obj interface{}
var err error
- if opt.listID > 0 {
+ if opt.listID != "" {
var list *madon.List
list, err = gClient.GetList(opt.listID)
obj = list
@@ -178,7 +178,7 @@
func listsGetAccountsRunE(cmd *cobra.Command, args []string) error {
opt := listsOpts
- if opt.listID <= 0 {
+ if opt.listID == "" {
return errors.New("missing list ID")
}
@@ -237,12 +237,12 @@
switch cmd.Name() {
case "create":
- if opt.listID > 0 {
+ if opt.listID != "" {
return errors.New("list ID should not be provided with create")
}
action = actionCreate
case "update":
- if opt.listID <= 0 {
+ if opt.listID == "" {
return errors.New("list ID is required")
}
action = actionUpdate
@@ -300,19 +300,19 @@
func listsAddRemoveAccountsRunE(cmd *cobra.Command, args []string) error {
opt := listsOpts
- if opt.listID <= 0 {
+ if opt.listID == "" {
return errors.New("missing list ID")
}
- var ids []int64
+ var ids []madon.ActivityID
var err error
ids, err = splitIDs(opt.accountIDs)
if err != nil {
return errors.New("cannot parse account IDs")
}
- if opt.accountID > 0 { // Allow --account-id
- ids = []int64{opt.accountID}
+ if opt.accountID != "" { // Allow --account-id
+ ids = []madon.ActivityID{opt.accountID}
}
if len(ids) < 1 {
return errors.New("missing account IDs")
--- a/cmd/madon.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/madon.go Mon Jan 23 16:39:02 2023 +0000
@@ -6,7 +6,6 @@
package cmd
import (
- "strconv"
"strings"
"github.com/McKael/madon/v2"
@@ -104,18 +103,16 @@
}
// splitIDs splits a list of IDs into an int64 array
-func splitIDs(ids string) (list []int64, err error) {
- var i int64
+func splitIDs(ids string) (list []madon.ActivityID, err error) {
if ids == "" {
return
}
l := strings.Split(ids, ",")
for _, s := range l {
- i, err = strconv.ParseInt(s, 10, 64)
- if err != nil {
+ if s == "" {
return
}
- list = append(list, i)
+ list = append(list, s)
}
return
}
--- a/cmd/media.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/media.go Mon Jan 23 16:39:02 2023 +0000
@@ -18,7 +18,7 @@
var mediaFlags *flag.FlagSet
var mediaOpts struct {
- mediaID int64
+ mediaID madon.ActivityID
filePath string
description string
focus string
@@ -48,7 +48,7 @@
RootCmd.AddCommand(mediaCmd)
mediaCmd.Flags().StringVar(&mediaOpts.filePath, "file", "", "Path of the media file")
- mediaCmd.Flags().Int64Var(&mediaOpts.mediaID, "update", 0, "Media to update (ID)")
+ mediaCmd.Flags().StringVar(&mediaOpts.mediaID, "update", "", "Media to update (ID)")
mediaCmd.Flags().StringVar(&mediaOpts.description, "description", "", "Plain text description")
mediaCmd.Flags().StringVar(&mediaOpts.focus, "focus", "", "Focal point")
@@ -61,10 +61,10 @@
opt := mediaOpts
if opt.filePath == "" {
- if opt.mediaID < 1 {
+ if opt.mediaID == "" {
return errors.New("no media file name provided")
}
- } else if opt.mediaID > 0 {
+ } else if opt.mediaID != "" {
return errors.New("cannot use both --file and --update")
}
@@ -102,13 +102,13 @@
}
// uploadFile uploads a media file and returns the attachment ID
-func uploadFile(filePath string) (int64, error) {
+func uploadFile(filePath string) (madon.ActivityID, error) {
attachment, err := gClient.UploadMedia(filePath, "", "")
if err != nil {
- return 0, err
+ return "", err
}
if attachment == nil {
- return 0, nil
+ return "", nil
}
return attachment.ID, nil
}
--- a/cmd/notifications.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/notifications.go Mon Jan 23 16:39:02 2023 +0000
@@ -17,7 +17,7 @@
var notificationsOpts struct {
list, clear, dismiss bool
- notifID int64
+ notifID madon.ActivityID
types string
excludeTypes string
}
@@ -50,7 +50,7 @@
notificationsCmd.Flags().BoolVar(¬ificationsOpts.list, "list", false, "List all current notifications")
notificationsCmd.Flags().BoolVar(¬ificationsOpts.clear, "clear", false, "Clear all current notifications")
notificationsCmd.Flags().BoolVar(¬ificationsOpts.dismiss, "dismiss", false, "Delete a notification")
- notificationsCmd.Flags().Int64Var(¬ificationsOpts.notifID, "notification-id", 0, "Get a notification")
+ notificationsCmd.Flags().StringVar(¬ificationsOpts.notifID, "notification-id", "", "Get a notification")
notificationsCmd.Flags().StringVar(¬ificationsOpts.types, "notification-types", "", "Filter notifications (mention, favourite, reblog, follow)")
notificationsCmd.Flags().StringVar(¬ificationsOpts.excludeTypes, "exclude-types", "", "Exclude notifications types (mention, favourite, reblog, follow)")
}
@@ -58,7 +58,7 @@
func notificationRunE(cmd *cobra.Command, args []string) error {
opt := notificationsOpts
- if !opt.list && !opt.clear && opt.notifID < 1 {
+ if !opt.list && !opt.clear && opt.notifID == "" {
return errors.New("missing parameters")
}
@@ -67,7 +67,7 @@
}
var limOpts *madon.LimitParams
- if accountsOpts.all || accountsOpts.limit > 0 || accountsOpts.sinceID > 0 || accountsOpts.maxID > 0 {
+ if accountsOpts.all || accountsOpts.limit > 0 || accountsOpts.sinceID != "" || accountsOpts.maxID != "" {
limOpts = new(madon.LimitParams)
limOpts.All = accountsOpts.all
}
@@ -75,11 +75,11 @@
if accountsOpts.limit > 0 {
limOpts.Limit = int(accountsOpts.limit)
}
- if accountsOpts.maxID > 0 {
- limOpts.MaxID = int64(accountsOpts.maxID)
+ if accountsOpts.maxID != "" {
+ limOpts.MaxID = accountsOpts.maxID
}
- if accountsOpts.sinceID > 0 {
- limOpts.SinceID = int64(accountsOpts.sinceID)
+ if accountsOpts.sinceID != "" {
+ limOpts.SinceID = accountsOpts.sinceID
}
var filterMap *map[string]bool
@@ -123,7 +123,7 @@
notifications = notifications[:accountsOpts.keep]
}
obj = notifications
- } else if opt.notifID > 0 {
+ } else if opt.notifID != "" {
if opt.dismiss {
err = gClient.DismissNotification(opt.notifID)
} else {
--- a/cmd/status.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/status.go Mon Jan 23 16:39:02 2023 +0000
@@ -20,14 +20,14 @@
var statusPostFlags *flag.FlagSet
var statusOpts struct {
- statusID int64
+ statusID madon.ActivityID
unset bool // TODO remove eventually?
// The following fields are used for the post/toot command
visibility string
sensitive bool
spoiler string
- inReplyToID int64
+ inReplyToID madon.ActivityID
mediaIDs string
mediaFilePath string
textFilePath string
@@ -39,6 +39,9 @@
limit, keep uint
//sinceID, maxID int64
all bool
+
+ // Used to indicate whether `in-reply-to` flag is present or not.
+ _hasReplyTo bool
}
func init() {
@@ -48,7 +51,7 @@
statusCmd.AddCommand(statusSubcommands...)
// Global flags
- statusCmd.PersistentFlags().Int64VarP(&statusOpts.statusID, "status-id", "s", 0, "Status ID number")
+ statusCmd.PersistentFlags().StringVarP(&statusOpts.statusID, "status-id", "s", "", "Status ID number")
statusCmd.PersistentFlags().UintVarP(&statusOpts.limit, "limit", "l", 0, "Limit number of API results")
statusCmd.PersistentFlags().UintVarP(&statusOpts.keep, "keep", "k", 0, "Limit number of results")
//statusCmd.PersistentFlags().Int64Var(&statusOpts.sinceID, "since-id", 0, "Request IDs greater than a value")
@@ -65,7 +68,7 @@
statusPostSubcommand.Flags().StringVar(&statusOpts.mediaIDs, "media-ids", "", "Comma-separated list of media IDs")
statusPostSubcommand.Flags().StringVarP(&statusOpts.mediaFilePath, "file", "f", "", "Media file name")
statusPostSubcommand.Flags().StringVar(&statusOpts.textFilePath, "text-file", "", "Text file name (message content)")
- statusPostSubcommand.Flags().Int64VarP(&statusOpts.inReplyToID, "in-reply-to", "r", 0, "Status ID to reply to")
+ statusPostSubcommand.Flags().StringVarP(&statusOpts.inReplyToID, "in-reply-to", "r", "", "Status ID to reply to")
statusPostSubcommand.Flags().BoolVar(&statusOpts.stdin, "stdin", false, "Read message content from standard input")
statusPostSubcommand.Flags().BoolVar(&statusOpts.addMentions, "add-mentions", false, "Add mentions when replying")
statusPostSubcommand.Flags().BoolVar(&statusOpts.sameVisibility, "same-visibility", false, "Use same visibility as original message (for replies)")
@@ -94,7 +97,7 @@
//Long: `TBW...`, // TODO
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// This is common to status and all status subcommands but "post"
- if statusOpts.statusID < 1 && cmd.Name() != "post" {
+ if statusOpts.statusID == "" && cmd.Name() != "post" {
return errors.New("missing status ID")
}
return madonInit(true)
@@ -241,6 +244,8 @@
The default visibility can be set in the configuration file with the option
'default_visibility' (or with an environmnent variable).`,
RunE: func(cmd *cobra.Command, args []string) error {
+ // Update the extra flag to reflect if `in-reply-to` was present or not
+ statusOpts._hasReplyTo = cmd.Flags().Lookup("in-reply-to").Changed
return statusSubcommandRunE(cmd.Name(), args)
},
}
--- a/cmd/suggestions.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/suggestions.go Mon Jan 23 16:39:02 2023 +0000
@@ -15,7 +15,7 @@
)
var suggestionsOpts struct {
- accountID int64
+ accountID madon.ActivityID
accountIDs string
//limit uint
@@ -41,7 +41,7 @@
suggestionsGetSubcommand.Flags().UintVarP(&suggestionsOpts.keep, "keep", "k", 0, "Limit number of results")
//suggestionsGetSubcommand.Flags().BoolVar(&suggestionsOpts.all, "all", false, "Fetch all results")
- suggestionsDeleteSubcommand.Flags().Int64VarP(&suggestionsOpts.accountID, "account-id", "a", 0, "Account ID number")
+ suggestionsDeleteSubcommand.Flags().StringVarP(&suggestionsOpts.accountID, "account-id", "a", "", "Account ID number")
suggestionsDeleteSubcommand.Flags().StringVar(&suggestionsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
}
@@ -116,13 +116,13 @@
func suggestionsDeleteRunE(cmd *cobra.Command, args []string) error {
opt := suggestionsOpts
- var ids []int64
+ var ids []madon.ActivityID
var err error
- if opt.accountID < 1 && len(opt.accountIDs) == 0 {
+ if opt.accountID == "" && len(opt.accountIDs) == 0 {
return errors.New("missing account IDs")
}
- if opt.accountID > 0 && len(opt.accountIDs) > 0 {
+ if opt.accountID != "" && len(opt.accountIDs) > 0 {
return errors.New("incompatible options")
}
@@ -130,8 +130,8 @@
if err != nil {
return errors.New("cannot parse account IDs")
}
- if opt.accountID > 0 { // Allow --account-id
- ids = []int64{opt.accountID}
+ if opt.accountID != "" { // Allow --account-id
+ ids = []madon.ActivityID{opt.accountID}
}
if len(ids) < 1 {
return errors.New("missing account IDs")
--- a/cmd/timelines.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/timelines.go Mon Jan 23 16:39:02 2023 +0000
@@ -17,7 +17,7 @@
var timelineOpts struct {
local, onlyMedia bool
limit, keep uint
- sinceID, maxID int64
+ sinceID, maxID madon.ActivityID
}
// timelineCmd represents the timelines command
@@ -47,25 +47,25 @@
timelineCmd.Flags().BoolVar(&timelineOpts.onlyMedia, "only-media", false, "Only statuses with media attachments")
timelineCmd.Flags().UintVarP(&timelineOpts.limit, "limit", "l", 0, "Limit number of API results")
timelineCmd.Flags().UintVarP(&timelineOpts.keep, "keep", "k", 0, "Limit number of results")
- timelineCmd.PersistentFlags().Int64Var(&timelineOpts.sinceID, "since-id", 0, "Request IDs greater than a value")
- timelineCmd.PersistentFlags().Int64Var(&timelineOpts.maxID, "max-id", 0, "Request IDs less (or equal) than a value")
+ timelineCmd.PersistentFlags().StringVar(&timelineOpts.sinceID, "since-id", "", "Request IDs greater than a value")
+ timelineCmd.PersistentFlags().StringVar(&timelineOpts.maxID, "max-id", "", "Request IDs less (or equal) than a value")
}
func timelineRunE(cmd *cobra.Command, args []string) error {
opt := timelineOpts
var limOpts *madon.LimitParams
- if opt.limit > 0 || opt.sinceID > 0 || opt.maxID > 0 {
+ if opt.limit > 0 || opt.sinceID != "" || opt.maxID != "" {
limOpts = new(madon.LimitParams)
}
if opt.limit > 0 {
limOpts.Limit = int(opt.limit)
}
- if opt.maxID > 0 {
+ if opt.maxID != "" {
limOpts.MaxID = opt.maxID
}
- if opt.sinceID > 0 {
+ if opt.sinceID != "" {
limOpts.SinceID = opt.sinceID
}
--- a/cmd/toot.go Thu Sep 22 16:37:07 2022 +0200
+++ b/cmd/toot.go Mon Jan 23 16:39:02 2023 +0000
@@ -29,7 +29,7 @@
tootAliasCmd.Flags().StringVar(&statusOpts.mediaIDs, "media-ids", "", "Comma-separated list of media IDs")
tootAliasCmd.Flags().StringVarP(&statusOpts.mediaFilePath, "file", "f", "", "Media attachment file name")
tootAliasCmd.Flags().StringVar(&statusOpts.textFilePath, "text-file", "", "Text file name (message content)")
- tootAliasCmd.Flags().Int64VarP(&statusOpts.inReplyToID, "in-reply-to", "r", 0, "Status ID to reply to")
+ tootAliasCmd.Flags().StringVarP(&statusOpts.inReplyToID, "in-reply-to", "r", "", "Status ID to reply to")
tootAliasCmd.Flags().BoolVar(&statusOpts.stdin, "stdin", false, "Read message content from standard input")
tootAliasCmd.Flags().BoolVar(&statusOpts.addMentions, "add-mentions", false, "Add mentions when replying")
tootAliasCmd.Flags().BoolVar(&statusOpts.sameVisibility, "same-visibility", false, "Use same visibility as original message (for replies)")
@@ -64,6 +64,8 @@
if err := madonInit(true); err != nil {
return err
}
+ // Update the extra flag to reflect if `in-reply-to` was present or not
+ statusOpts._hasReplyTo = cmd.Flags().Lookup("in-reply-to").Changed
return statusSubcommandRunE("post", args)
},
}
@@ -85,7 +87,12 @@
return nil, errors.Errorf("invalid visibility argument value '%s'", opt.visibility)
}
- if opt.inReplyToID < 0 {
+ // Bit of a fudge but there's no easy way to tell if a string flag
+ // is empty by default or empty by assignment. Can't use a pointer
+ // and have `nil` be "unset" because Cobra will crash if we send it
+ // a `nil` as the recepient for a flag variable. Hence using an
+ // extra struct member as a flag to indicate set/unset.
+ if opt._hasReplyTo && opt.inReplyToID == "" {
return nil, errors.New("invalid in-reply-to argument value")
}
@@ -98,7 +105,7 @@
return nil, errors.New("toot is empty")
}
- if opt.inReplyToID > 0 {
+ if opt.inReplyToID != "" {
var initialStatus *madon.Status
var preserveVis bool
if opt.sameVisibility &&
@@ -143,7 +150,7 @@
if err != nil {
return nil, errors.Wrap(err, "cannot attach media file")
}
- if fileMediaID > 0 {
+ if fileMediaID != "" {
ids = append(ids, fileMediaID)
}
}
--- a/printer/plainprinter.go Thu Sep 22 16:37:07 2022 +0200
+++ b/printer/plainprinter.go Mon Jan 23 16:39:02 2023 +0000
@@ -175,7 +175,7 @@
}
func (p *PlainPrinter) plainPrintAccount(a *madon.Account, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Account ID", "%d (%s)", a.ID, a.Username)
+ indentedPrint(w, indent, true, false, "Account ID", "%s (%s)", a.ID, a.Username)
indentedPrint(w, indent, false, false, "User ID", "%s", a.Acct)
indentedPrint(w, indent, false, false, "Display name", "%s", a.DisplayName)
indentedPrint(w, indent, false, false, "Creation date", "%v", a.CreatedAt.Local())
@@ -192,7 +192,7 @@
indentedPrint(w, indent, false, true, "User note", "%s", html2string(a.Note)) // XXX too long?
if a.Moved != nil {
m := a.Moved
- indentedPrint(w, indent+p.Indent, true, false, "Moved to account ID", "%d (%s)", m.ID, m.Username)
+ indentedPrint(w, indent+p.Indent, true, false, "Moved to account ID", "%s (%s)", m.ID, m.Username)
indentedPrint(w, indent+p.Indent, false, false, "New user ID", "%s", m.Acct)
indentedPrint(w, indent+p.Indent, false, false, "New display name", "%s", m.DisplayName)
}
@@ -218,7 +218,7 @@
}
func (p *PlainPrinter) plainPrintAttachment(a *madon.Attachment, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Attachment ID", "%d", a.ID)
+ indentedPrint(w, indent, true, false, "Attachment ID", "%s", a.ID)
indentedPrint(w, indent, false, false, "Type", "%s", a.Type)
indentedPrint(w, indent, false, false, "Local URL", "%s", a.URL)
if a.RemoteURL != nil {
@@ -269,7 +269,7 @@
indentedPrint(w, indent, false, true, "Version", "%s", i.Version)
if i.ContactAccount != nil {
c := i.ContactAccount
- indentedPrint(w, indent+p.Indent, true, false, "Contact account ID", "%d (%s)", c.ID, c.Username)
+ indentedPrint(w, indent+p.Indent, true, false, "Contact account ID", "%s (%s)", c.ID, c.Username)
indentedPrint(w, indent+p.Indent, false, false, "Contact user ID", "%s", c.Acct)
indentedPrint(w, indent+p.Indent, false, false, "Contact display name", "%s", c.DisplayName)
}
@@ -282,17 +282,17 @@
}
func (p *PlainPrinter) plainPrintList(l *madon.List, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "List ID", "%d", l.ID)
+ indentedPrint(w, indent, true, false, "List ID", "%s", l.ID)
indentedPrint(w, indent, false, false, "Title", "%s", l.Title)
return nil
}
func (p *PlainPrinter) plainPrintNotification(n *madon.Notification, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Notification ID", "%d", n.ID)
+ indentedPrint(w, indent, true, false, "Notification ID", "%s", n.ID)
indentedPrint(w, indent, false, false, "Type", "%s", n.Type)
indentedPrint(w, indent, false, false, "Timestamp", "%v", n.CreatedAt.Local())
if n.Account != nil {
- indentedPrint(w, indent+p.Indent, true, false, "Account", "(%d) @%s - %s",
+ indentedPrint(w, indent+p.Indent, true, false, "Account", "(%s) @%s - %s",
n.Account.ID, n.Account.Acct, n.Account.DisplayName)
}
if n.Status != nil {
@@ -302,7 +302,7 @@
}
func (p *PlainPrinter) plainPrintRelationship(r *madon.Relationship, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Account ID", "%d", r.ID)
+ indentedPrint(w, indent, true, false, "Account ID", "%s", r.ID)
indentedPrint(w, indent, false, false, "Following", "%v", r.Following)
//indentedPrint(w, indent, false, false, "Showing reblogs", "%v", r.ShowingReblogs)
indentedPrint(w, indent, false, false, "Followed-by", "%v", r.FollowedBy)
@@ -315,7 +315,7 @@
}
func (p *PlainPrinter) plainPrintReport(r *madon.Report, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Report ID", "%d", r.ID)
+ indentedPrint(w, indent, true, false, "Report ID", "%s", r.ID)
indentedPrint(w, indent, false, false, "Action taken", "%s", r.ActionTaken)
return nil
}
@@ -342,7 +342,7 @@
}
func (p *PlainPrinter) plainPrintStatus(s *madon.Status, w io.Writer, indent string) error {
- indentedPrint(w, indent, true, false, "Status ID", "%d", s.ID)
+ indentedPrint(w, indent, true, false, "Status ID", "%s", s.ID)
if s.Account != nil {
author := s.Account.Acct
if s.Account.DisplayName != "" {
@@ -370,8 +370,8 @@
}
indentedPrint(w, indent, false, false, "Contents", "%s", html2string(s.Content))
- if s.InReplyToID != nil && *s.InReplyToID > 0 {
- indentedPrint(w, indent, false, false, "In-Reply-To", "%d", *s.InReplyToID)
+ if s.InReplyToID != nil && *s.InReplyToID != "" {
+ indentedPrint(w, indent, false, false, "In-Reply-To", "%s", *s.InReplyToID)
}
if s.Reblogged {
indentedPrint(w, indent, false, false, "Reblogged", "%v", s.Reblogged)
@@ -380,7 +380,7 @@
// Display minimum details of attachments
//return p.PrintObj(s.MediaAttachments, w, indent+p.Indent)
for _, a := range s.MediaAttachments {
- indentedPrint(w, indent+p.Indent, true, false, "Attachment ID", "%d", a.ID)
+ indentedPrint(w, indent+p.Indent, true, false, "Attachment ID", "%s", a.ID)
if a.TextURL != nil && *a.TextURL != "" {
indentedPrint(w, indent+p.Indent, true, false, "Text URL", "%s", *a.TextURL)
} else if a.URL != "" {