Merge branch 'master' of https://github.com/McKael/madonctl
authorMikael Berthe <mikael@lilotux.net>
Thu, 06 Sep 2018 01:10:15 +0200
changeset 233 a141105804f7
parent 230 c961191a6b8f (diff)
parent 232 5fc930cd4e0f (current diff)
child 234 f5cd55622194
Merge branch 'master' of https://github.com/McKael/madonctl
--- a/cmd/accounts.go	Mon Jun 11 06:38:55 2018 +0200
+++ b/cmd/accounts.go	Thu Sep 06 01:10:15 2018 +0200
@@ -22,24 +22,28 @@
 var accountsOpts struct {
 	accountID             int64
 	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
-	avatar, header        string // For account update
-	locked                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        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
 }
 
 func init() {
@@ -86,7 +90,12 @@
 	accountUpdateSubcommand.Flags().StringVar(&accountsOpts.note, "note", "", "User note (a.k.a. bio)")
 	accountUpdateSubcommand.Flags().StringVar(&accountsOpts.avatar, "avatar", "", "User avatar image")
 	accountUpdateSubcommand.Flags().StringVar(&accountsOpts.header, "header", "", "User header image")
+	accountUpdateSubcommand.Flags().StringArrayVar(&accountsOpts.profileFields, "profile-field", nil, "Profile metadata field (NAME=VALUE)")
+	accountUpdateSubcommand.Flags().StringVar(&accountsOpts.defaultLanguage, "default-language", "", "Default toots language (iso 639 code)")
+	accountUpdateSubcommand.Flags().StringVar(&accountsOpts.defaultPrivacy, "default-privacy", "", "Default toot privacy (public, unlisted, private)")
+	accountUpdateSubcommand.Flags().BoolVar(&accountsOpts.defaultSensitive, "default-sensitive", false, "Mark medias as sensitive by default")
 	accountUpdateSubcommand.Flags().BoolVar(&accountsOpts.locked, "locked", false, "Following account requires approval")
+	accountUpdateSubcommand.Flags().BoolVar(&accountsOpts.bot, "bot", false, "Set as service (automated) account")
 
 	// Those variables will be used to check if the options were
 	// explicitly set or not
@@ -170,9 +179,12 @@
 	accountFollowSubcommand,
 	accountBlockSubcommand,
 	accountMuteSubcommand,
+	accountPinSubcommand,
+	accountUnpinSubcommand,
 	accountRelationshipsSubcommand,
 	accountReportsSubcommand,
 	accountUpdateSubcommand,
+	accountListEndorsementsSubcommand,
 }
 
 var accountSearchSubcommand = &cobra.Command{
@@ -246,6 +258,33 @@
 	},
 }
 
+var accountPinSubcommand = &cobra.Command{
+	Use:     "pin",
+	Short:   "Endorse (pin) the account",
+	Aliases: []string{"endorse"},
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE(cmd.Name(), args)
+	},
+}
+
+var accountUnpinSubcommand = &cobra.Command{
+	Use:     "unpin",
+	Short:   "Cancel endorsement of an account",
+	Aliases: []string{"disavow"},
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE(cmd.Name(), args)
+	},
+}
+
+var accountListEndorsementsSubcommand = &cobra.Command{
+	Use:     "pinned",
+	Short:   `Display the list of pinned (endorsed) accounts`,
+	Aliases: []string{"list-endorsements", "get-endorsements"},
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE(cmd.Name(), args)
+	},
+}
+
 var accountRelationshipsSubcommand = &cobra.Command{
 	Use:   "relationships --account-ids ACC1,ACC2...",
 	Short: "List relationships with the accounts",
@@ -364,7 +403,7 @@
 	switch subcmd {
 	case "show", "search", "update":
 		// These subcommands do not require an account ID
-	case "favourites", "blocks", "mutes":
+	case "favourites", "blocks", "mutes", "pinned":
 		// Those subcommands can not use an account ID
 		if opt.accountID > 0 {
 			return errors.New("useless account ID")
@@ -564,6 +603,14 @@
 			relationship, err = gClient.MuteAccount(opt.accountID, muteNotif)
 		}
 		obj = relationship
+	case "pin", "unpin":
+		var relationship *madon.Relationship
+		if subcmd == "unpin" {
+			relationship, err = gClient.UnpinAccount(opt.accountID)
+		} else {
+			relationship, err = gClient.PinAccount(opt.accountID)
+		}
+		obj = relationship
 	case "favourites":
 		var statusList []madon.Status
 		statusList, err = gClient.GetFavourites(limOpts)
@@ -585,6 +632,13 @@
 			accountList = accountList[:opt.keep]
 		}
 		obj = accountList
+	case "pinned":
+		var accountList []madon.Account
+		accountList, err = gClient.GetEndorsements(limOpts)
+		if opt.keep > 0 && len(accountList) > int(opt.keep) {
+			accountList = accountList[:opt.keep]
+		}
+		obj = accountList
 	case "relationships":
 		var ids []int64
 		ids, err = splitIDs(opt.accountIDs)
@@ -623,27 +677,65 @@
 		report, err = gClient.ReportUser(opt.accountID, ids, opt.comment)
 		obj = report
 	case "update":
-		var dn, note, avatar, header *string
-		var locked *bool
+		var updateParams madon.UpdateAccountParams
+		var source *madon.SourceParams
 		change := false
+
 		if accountUpdateFlags.Lookup("display-name").Changed {
-			dn = &opt.displayName
+			updateParams.DisplayName = &opt.displayName
 			change = true
 		}
 		if accountUpdateFlags.Lookup("note").Changed {
-			note = &opt.note
+			updateParams.Note = &opt.note
 			change = true
 		}
 		if accountUpdateFlags.Lookup("avatar").Changed {
-			avatar = &opt.avatar
+			updateParams.AvatarImagePath = &opt.avatar
 			change = true
 		}
 		if accountUpdateFlags.Lookup("header").Changed {
-			header = &opt.header
+			updateParams.HeaderImagePath = &opt.header
 			change = true
 		}
 		if accountUpdateFlags.Lookup("locked").Changed {
-			locked = &opt.locked
+			updateParams.Locked = &opt.locked
+			change = true
+		}
+		if accountUpdateFlags.Lookup("bot").Changed {
+			updateParams.Bot = &opt.bot
+			change = true
+		}
+		if accountUpdateFlags.Lookup("default-language").Changed {
+			if source == nil {
+				source = &madon.SourceParams{}
+			}
+			source.Language = &opt.defaultLanguage
+			change = true
+		}
+		if accountUpdateFlags.Lookup("default-privacy").Changed {
+			if source == nil {
+				source = &madon.SourceParams{}
+			}
+			source.Privacy = &opt.defaultPrivacy
+			change = true
+		}
+		if accountUpdateFlags.Lookup("default-sensitive").Changed {
+			if source == nil {
+				source = &madon.SourceParams{}
+			}
+			source.Sensitive = &opt.defaultSensitive
+			change = true
+		}
+		if accountUpdateFlags.Lookup("profile-field").Changed {
+			var fa = []madon.Field{}
+			for _, f := range opt.profileFields {
+				kv := strings.SplitN(f, "=", 2)
+				if len(kv) != 2 {
+					return errors.New("cannot parse field")
+				}
+				fa = append(fa, madon.Field{Name: kv[0], Value: kv[1]})
+			}
+			updateParams.FieldsAttributes = &fa
 			change = true
 		}
 
@@ -651,8 +743,10 @@
 			return errors.New("missing parameters")
 		}
 
+		updateParams.Source = source
+
 		var account *madon.Account
-		account, err = gClient.UpdateAccount(dn, note, avatar, header, locked)
+		account, err = gClient.UpdateAccount(updateParams)
 		obj = account
 	default:
 		return errors.New("accountSubcommand: internal error")
--- a/cmd/status.go	Mon Jun 11 06:38:55 2018 +0200
+++ b/cmd/status.go	Thu Sep 06 01:10:15 2018 +0200
@@ -194,7 +194,9 @@
 	Use:     "post",
 	Aliases: []string{"toot", "pouet"},
 	Short:   "Post a message (same as 'madonctl toot')",
-	Example: `  madonctl status post --spoiler Warning "Hello, World"
+	Example: `  madonctl status post "Hello, World"
+  madonctl status post --spoiler Warning "Spoiled"
+  madonctl status toot --visibility private "To my followers only"
   madonctl status toot --sensitive --file image.jpg Image
   madonctl status post --media-ids ID1,ID2,ID3 Image
   madonctl status toot --text-file message.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/suggestions.go	Thu Sep 06 01:10:15 2018 +0200
@@ -0,0 +1,156 @@
+// Copyright © 2018 Mikael Berthe <mikael@lilotux.net>
+//
+// Licensed under the MIT license.
+// Please see the LICENSE file is this directory.
+
+package cmd
+
+import (
+	"os"
+
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+
+	"github.com/McKael/madon"
+)
+
+var suggestionsOpts struct {
+	accountID  int64
+	accountIDs string
+
+	//limit uint
+	keep uint
+	//all bool
+}
+
+//suggestionsCmd represents the suggestions command
+var suggestionsCmd = &cobra.Command{
+	Use:     "suggestions",
+	Aliases: []string{"suggestion"},
+	Short:   "Display and remove the follow suggestions",
+	RunE:    suggestionsGetRunE, // Defaults to list
+}
+
+func init() {
+	RootCmd.AddCommand(suggestionsCmd)
+
+	// Subcommands
+	suggestionsCmd.AddCommand(suggestionsSubcommands...)
+
+	//suggestionsGetSubcommand.Flags().UintVarP(&suggestionsOpts.limit, "limit", "l", 0, "Limit number of API results")
+	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().StringVar(&suggestionsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
+}
+
+var suggestionsSubcommands = []*cobra.Command{
+	suggestionsGetSubcommand,
+	suggestionsDeleteSubcommand,
+}
+
+var suggestionsGetSubcommand = &cobra.Command{
+	Use:     "list",
+	Short:   "Display the suggestions (default subcommand)",
+	Long:    `Display the list of account suggestions.`,
+	Aliases: []string{"ls", "get", "display", "show"},
+	RunE:    suggestionsGetRunE,
+}
+
+var suggestionsDeleteSubcommand = &cobra.Command{
+	Use:     "delete",
+	Short:   "Remove an account from the suggestion list",
+	Aliases: []string{"remove", "del", "rm"},
+	RunE:    suggestionsDeleteRunE,
+}
+
+func suggestionsGetRunE(cmd *cobra.Command, args []string) error {
+	opt := suggestionsOpts
+
+	/*
+		// Note: The API currently does not support pagination
+		// Set up LimitParams
+		var limOpts *madon.LimitParams
+		if opt.all || opt.limit > 0 {
+			limOpts = new(madon.LimitParams)
+			limOpts.All = opt.all
+		}
+		if opt.limit > 0 {
+			limOpts.Limit = int(opt.limit)
+		}
+	*/
+
+	// We need to be logged in
+	if err := madonInit(true); err != nil {
+		return err
+	}
+
+	var obj interface{}
+	var err error
+
+	var accountList []madon.Account
+	accountList, err = gClient.GetSuggestions(nil)
+
+	if opt.keep > 0 && len(accountList) > int(opt.keep) {
+		accountList = accountList[:opt.keep]
+	}
+
+	obj = accountList
+
+	if err != nil {
+		errPrint("Error: %s", err.Error())
+		os.Exit(1)
+	}
+	if obj == nil {
+		return nil
+	}
+
+	p, err := getPrinter()
+	if err != nil {
+		errPrint("Error: %v", err)
+		os.Exit(1)
+	}
+	return p.printObj(obj)
+}
+
+func suggestionsDeleteRunE(cmd *cobra.Command, args []string) error {
+	opt := suggestionsOpts
+	var ids []int64
+	var err error
+
+	if opt.accountID < 1 && len(opt.accountIDs) == 0 {
+		return errors.New("missing account IDs")
+	}
+	if opt.accountID > 0 && len(opt.accountIDs) > 0 {
+		return errors.New("incompatible options")
+	}
+
+	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 len(ids) < 1 {
+		return errors.New("missing account IDs")
+	}
+
+	// We need to be logged in
+	if err := madonInit(true); err != nil {
+		return err
+	}
+
+	for _, id := range ids {
+		if e := gClient.DeleteSuggestion(id); err != nil {
+			errPrint("Cannot remove account %d: %s", id, e)
+			err = e
+		}
+	}
+
+	if err != nil {
+		os.Exit(1)
+	}
+	return nil
+}
--- a/cmd/toot.go	Mon Jun 11 06:38:55 2018 +0200
+++ b/cmd/toot.go	Thu Sep 06 01:10:15 2018 +0200
@@ -49,6 +49,7 @@
 	Aliases: []string{"post", "pouet"},
 	Short:   "Post a message (toot)",
 	Example: `  madonctl toot message
+  madonctl toot --visibility private "To my followers only"
   madonctl toot --spoiler Warning "Hello, World"
   madonctl status post --media-ids ID1,ID2 "Here are the photos"
   madonctl post --sensitive --file image.jpg Image
@@ -147,7 +148,15 @@
 		}
 	}
 
-	return gClient.PostStatus(tootText, opt.inReplyToID, ids, opt.sensitive, opt.spoiler, opt.visibility)
+	postParam := madon.PostStatusParams{
+		Text:        tootText,
+		InReplyTo:   opt.inReplyToID,
+		MediaIDs:    ids,
+		Sensitive:   opt.sensitive,
+		SpoilerText: opt.spoiler,
+		Visibility:  opt.visibility,
+	}
+	return gClient.PostStatus(postParam)
 }
 
 func mentionsList(s *madon.Status) (string, error) {
--- a/cmd/version.go	Mon Jun 11 06:38:55 2018 +0200
+++ b/cmd/version.go	Thu Sep 06 01:10:15 2018 +0200
@@ -23,7 +23,7 @@
 }
 
 // VERSION of the madonctl application
-var VERSION = "2.3.1"
+var VERSION = "2.4.0-dev"
 
 var versionCmd = &cobra.Command{
 	Use:   "version",
--- a/printer/plainprinter.go	Mon Jun 11 06:38:55 2018 +0200
+++ b/printer/plainprinter.go	Thu Sep 06 01:10:15 2018 +0200
@@ -288,6 +288,7 @@
 	indentedPrint(w, indent, false, false, "Blocking", "%v", r.Blocking)
 	indentedPrint(w, indent, false, false, "Muting", "%v", r.Muting)
 	indentedPrint(w, indent, false, false, "Muting notifications", "%v", r.MutingNotifications)
+	indentedPrint(w, indent, false, false, "Endorsed", "%v", r.Endorsed)
 	indentedPrint(w, indent, false, false, "Requested", "%v", r.Requested)
 	return nil
 }
@@ -312,7 +313,8 @@
 	if len(r.Hashtags) > 0 {
 		indentedPrint(w, indent, false, false, "Hashtags", "")
 		for _, tag := range r.Hashtags {
-			indentedPrint(w, indent+p.Indent, true, false, "Tag", "%s", tag)
+			indentedPrint(w, indent+p.Indent, true, false, "Tag", "%s", tag.Name)
+			indentedPrint(w, indent+p.Indent, false, true, "URL", "%s", tag.URL)
 		}
 	}
 	return nil
--- a/templates/themes/ansi-dark/relationship.tmpl	Mon Jun 11 06:38:55 2018 +0200
+++ b/templates/themes/ansi-dark/relationship.tmpl	Thu Sep 06 01:10:15 2018 +0200
@@ -1,8 +1,10 @@
 - Account ID: {{color "red"}}{{.id}}{{color "reset"}}
   Following:      {{.following}}
-{{- if .showing_reblogs}}  Showing boosts: {{.showing_reblogs}}{{end}}
+{{- if .showing_reblogs}}
+  Showing boosts: {{.showing_reblogs}}{{end}}
   Followed-by:    {{.followed_by}}
   Blocking:       {{.blocking}}
   Muting:         {{.muting}}
   Muting notif.:  {{.muting}}
+  Endorsed:       {{.endorsed}}
   Requested:      {{.requested}}
--- a/templates/themes/ansi-dark/results.tmpl	Mon Jun 11 06:38:55 2018 +0200
+++ b/templates/themes/ansi-dark/results.tmpl	Thu Sep 06 01:10:15 2018 +0200
@@ -33,5 +33,5 @@
       Remote URL: {{.remote_url}}{{end}}{{end}}{{end}}{{/* of range */}}{{end}}{{/* of statuses */}}
 {{- with .hashtags}}{{color ",,bold"}}Hashtags:{{color "reset"}}
 {{- range .}}
-  - {{.}}{{end}}{{/* of range */}}
+  - Tag: {{.name}}{{end}}{{/* of range */}}
 {{end}}{{/* of statuses */ -}}
--- a/templates/themes/ansi/relationship.tmpl	Mon Jun 11 06:38:55 2018 +0200
+++ b/templates/themes/ansi/relationship.tmpl	Thu Sep 06 01:10:15 2018 +0200
@@ -1,8 +1,10 @@
 - Account ID: {{color "red"}}{{.id}}{{color "reset"}}
   Following:      {{.following}}
-{{- if .showing_reblogs}}  Showing boosts: {{.showing_reblogs}}{{end}}
+{{- if .showing_reblogs}}
+  Showing boosts: {{.showing_reblogs}}{{end}}
   Followed-by:    {{.followed_by}}
   Blocking:       {{.blocking}}
   Muting:         {{.muting}}
   Muting notif.:  {{.muting}}
+  Endorsed:       {{.endorsed}}
   Requested:      {{.requested}}
--- a/templates/themes/ansi/results.tmpl	Mon Jun 11 06:38:55 2018 +0200
+++ b/templates/themes/ansi/results.tmpl	Thu Sep 06 01:10:15 2018 +0200
@@ -33,5 +33,5 @@
       Remote URL: {{.remote_url}}{{end}}{{end}}{{end}}{{/* of range */}}{{end}}{{/* of statuses */}}
 {{- with .hashtags}}{{color ",,bold"}}Hashtags:{{color "reset"}}
 {{- range .}}
-  - {{.}}{{end}}{{/* of range */}}
+  - Tag: {{.name}}{{end}}{{/* of range */}}
 {{end}}{{/* of statuses */ -}}