cmd/accounts.go
changeset 0 5abace724584
child 6 5228e517c455
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/accounts.go	Wed Apr 19 19:08:47 2017 +0200
@@ -0,0 +1,391 @@
+// Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
+//
+// Licensed under the MIT license.
+// Please see the LICENSE file is this directory.
+
+package cmd
+
+import (
+	"errors"
+	"strings"
+
+	"github.com/spf13/cobra"
+
+	"github.com/McKael/madon"
+)
+
+var accountsOpts struct {
+	accountID                 int
+	unset                     bool // TODO remove eventually?
+	limit                     int
+	onlyMedia, excludeReplies bool   // For acccount statuses
+	remoteUID                 string // 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
+	show                      bool   // For account reports
+}
+
+func init() {
+	RootCmd.AddCommand(accountsCmd)
+
+	// Subcommands
+	accountsCmd.AddCommand(accountSubcommands...)
+
+	// Global flags
+	accountsCmd.PersistentFlags().IntVarP(&accountsOpts.accountID, "account-id", "a", 0, "Account ID number")
+	//accountsCmd.PersistentFlags().IntVarP(&accountsOpts.limit, "limit", "l", 0, "Limit number of results")
+
+	// Subcommand flags
+	accountStatusesSubcommand.Flags().BoolVar(&accountsOpts.onlyMedia, "only-media", false, "Only statuses with media attachments")
+	accountStatusesSubcommand.Flags().BoolVar(&accountsOpts.excludeReplies, "exclude-replies", false, "Exclude replies to other statuses")
+
+	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.list, "list", false, "List pending follow requests")
+	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.acceptFR, "accept", false, "Accept the follow request from the account ID")
+	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.rejectFR, "reject", false, "Reject the follow request from the account ID")
+
+	accountBlockSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unblock the account")
+	accountMuteSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unmute the account")
+	accountFollowSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unfollow the account")
+	accountFollowSubcommand.Flags().StringVarP(&accountsOpts.remoteUID, "remote", "r", "", "Follow remote account (user@domain)")
+
+	accountRelationshipsSubcommand.Flags().StringVar(&accountsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
+
+	accountReportsSubcommand.Flags().StringVar(&accountsOpts.statusIDs, "status-ids", "", "Comma-separated list of status IDs")
+	accountReportsSubcommand.Flags().StringVar(&accountsOpts.comment, "comment", "", "Report comment")
+	accountReportsSubcommand.Flags().BoolVar(&accountsOpts.list, "list", false, "List current user reports")
+}
+
+// accountsCmd represents the accounts command
+// This command does nothing without a subcommand
+var accountsCmd = &cobra.Command{
+	Use:     "accounts [--account-id ID] subcommand",
+	Aliases: []string{"account"},
+	Short:   "Account-related functions",
+	//Long:    `TBW...`, // TODO
+	//PersistentPreRunE: func(cmd *cobra.Command, args []string) error {},
+}
+
+// Note: Some account subcommands are not defined in this file.
+var accountSubcommands = []*cobra.Command{
+	&cobra.Command{
+		Use: "show",
+		Long: `Displays the details about the requested account.
+If no account ID is specified, the current user account is used.`,
+		Aliases: []string{"display"},
+		Short:   "Display the account",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:   "followers",
+		Short: "Display the accounts following the specified account",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:   "following",
+		Short: "Display the accounts followed by the specified account",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:     "favourites",
+		Aliases: []string{"favorites", "favourited", "favorited"},
+		Short:   "Display the user's favourites",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:     "blocks",
+		Aliases: []string{"blocked"},
+		Short:   "Display the user's blocked accounts",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:     "mutes",
+		Aliases: []string{"muted"},
+		Short:   "Display the user's muted accounts",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	&cobra.Command{
+		Use:   "search TEXT",
+		Short: "Search for user accounts",
+		Long: `Search for user accounts.
+The server will lookup an account remotely if the search term is in the
+username@domain format and not yet in the database.`,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return accountSubcommandsRunE(cmd.Name(), args)
+		},
+	},
+	accountStatusesSubcommand,
+	accountFollowRequestsSubcommand,
+	accountFollowSubcommand,
+	accountBlockSubcommand,
+	accountMuteSubcommand,
+	accountRelationshipsSubcommand,
+	accountReportsSubcommand,
+}
+
+var accountStatusesSubcommand = &cobra.Command{
+	Use:     "statuses",
+	Aliases: []string{"st"},
+	Short:   "Display the account statuses",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE(cmd.Name(), args)
+	},
+}
+
+var accountFollowRequestsSubcommand = &cobra.Command{
+	Use:     "follow-requests",
+	Aliases: []string{"follow-request", "fr"},
+	Example: `  madonctl accounts follow-requests --list
+  madonctl accounts follow-requests --account-id X --accept
+  madonctl accounts follow-requests --account-id Y --reject`,
+	Short: "List, accept or deny a follow request",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("follow-requests", args)
+	},
+}
+var accountFollowSubcommand = &cobra.Command{
+	Use:   "follow",
+	Short: "Follow or unfollow the account",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("follow", args)
+	},
+}
+
+var accountBlockSubcommand = &cobra.Command{
+	Use:   "block",
+	Short: "Block or unblock the account",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("block", args)
+	},
+}
+
+var accountMuteSubcommand = &cobra.Command{
+	Use:   "mute",
+	Short: "Mute or unmute the account",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("mute", args)
+	},
+}
+
+var accountRelationshipsSubcommand = &cobra.Command{
+	Use:   "relationships --account-ids ACC1,ACC2...",
+	Short: "List relationships with the accounts",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("relationships", args)
+	},
+}
+
+var accountReportsSubcommand = &cobra.Command{
+	Use:   "reports",
+	Short: "List reports or report a user account",
+	Example: `  madonctl accounts reports --list
+  madonctl accounts reports --account-id ACCOUNT --status-ids ID... --comment TEXT`,
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return accountSubcommandsRunE("reports", args)
+	},
+}
+
+// accountSubcommandsRunE is a generic function for status subcommands
+func accountSubcommandsRunE(subcmd string, args []string) error {
+	opt := accountsOpts
+
+	switch subcmd {
+	case "show", "search":
+		// These subcommands do not require an account ID
+	case "favourites", "blocks", "mutes":
+		// Those subcommands can not use an account ID
+		if opt.accountID > 0 {
+			return errors.New("useless account ID")
+		}
+	case "follow":
+		if opt.accountID < 1 && opt.remoteUID == "" {
+			return errors.New("missing account ID or URI")
+		}
+		if opt.accountID > 0 && opt.remoteUID != "" {
+			return errors.New("cannot use both account ID and URI")
+		}
+		if opt.unset && opt.accountID < 1 {
+			return errors.New("unfollowing requires an account ID")
+		}
+	case "follow-requests":
+		if opt.list {
+			if opt.acceptFR || opt.rejectFR {
+				return errors.New("incompatible options")
+			}
+		} else {
+			if !opt.acceptFR && !opt.rejectFR { // No flag
+				return errors.New("missing parameter (--list, --accept or --reject)")
+			}
+			// This is a FR reply
+			if opt.acceptFR && opt.rejectFR {
+				return errors.New("incompatible options")
+			}
+			if opt.accountID < 1 {
+				return errors.New("missing account ID")
+			}
+		}
+	case "relationships":
+		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")
+		}
+	case "reports":
+		if opt.list {
+			break // No argument needed
+		}
+		if opt.accountID < 1 || len(opt.statusIDs) == 0 || opt.comment == "" {
+			return errors.New("missing parameter")
+		}
+	default:
+		// The other subcommands here require an account ID
+		if opt.accountID < 1 {
+			return errors.New("missing account ID")
+		}
+	}
+
+	// All account subcommands need to have signed in
+	if err := madonInit(true); err != nil {
+		return err
+	}
+
+	var obj interface{}
+	var err error
+
+	switch subcmd {
+	case "show":
+		var account *madon.Account
+		if opt.accountID > 0 {
+			account, err = gClient.GetAccount(opt.accountID)
+		} else {
+			account, err = gClient.GetCurrentAccount()
+		}
+		obj = account
+	case "search":
+		var accountList []madon.Account
+		limit := 0 // TODO use a global flag
+		accountList, err = gClient.SearchAccounts(strings.Join(args, " "), limit)
+		obj = accountList
+	case "followers":
+		var accountList []madon.Account
+		accountList, err = gClient.GetAccountFollowers(opt.accountID)
+		obj = accountList
+	case "following":
+		var accountList []madon.Account
+		accountList, err = gClient.GetAccountFollowing(opt.accountID)
+		obj = accountList
+	case "statuses":
+		var statusList []madon.Status
+		statusList, err = gClient.GetAccountStatuses(opt.accountID, opt.onlyMedia, opt.excludeReplies)
+		obj = statusList
+	case "follow":
+		if opt.unset {
+			err = gClient.UnfollowAccount(opt.accountID)
+		} else {
+			if opt.accountID > 0 {
+				err = gClient.FollowAccount(opt.accountID)
+			} else {
+				var account *madon.Account
+				account, err = gClient.FollowRemoteAccount(opt.remoteUID)
+				obj = account
+			}
+		}
+	case "follow-requests":
+		if opt.list {
+			var followRequests []madon.Account
+			followRequests, err = gClient.GetAccountFollowRequests()
+			obj = followRequests
+		} else {
+			err = gClient.FollowRequestAuthorize(opt.accountID, !opt.rejectFR)
+		}
+	case "block":
+		if opt.unset {
+			err = gClient.UnblockAccount(opt.accountID)
+		} else {
+			err = gClient.BlockAccount(opt.accountID)
+		}
+	case "mute":
+		if opt.unset {
+			err = gClient.UnmuteAccount(opt.accountID)
+		} else {
+			err = gClient.MuteAccount(opt.accountID)
+		}
+	case "favourites":
+		var statusList []madon.Status
+		statusList, err = gClient.GetFavourites()
+		obj = statusList
+	case "blocks":
+		var accountList []madon.Account
+		accountList, err = gClient.GetBlockedAccounts()
+		obj = accountList
+	case "mutes":
+		var accountList []madon.Account
+		accountList, err = gClient.GetMutedAccounts()
+		obj = accountList
+	case "relationships":
+		var ids []int
+		ids, err = splitIDs(opt.accountIDs)
+		if err != nil {
+			return errors.New("cannot parse account IDs")
+		}
+		if opt.accountID > 0 { // Allow --account-id
+			ids = []int{opt.accountID}
+		}
+		if len(ids) < 1 {
+			return errors.New("missing account IDs")
+		}
+		var relationships []madon.Relationship
+		relationships, err = gClient.GetAccountRelationships(ids)
+		obj = relationships
+	case "reports":
+		if opt.list {
+			var reports []madon.Report
+			reports, err = gClient.GetReports()
+			obj = reports
+			break
+		}
+		// Send a report
+		var ids []int
+		ids, err = splitIDs(opt.statusIDs)
+		if err != nil {
+			return errors.New("cannot parse status IDs")
+		}
+		if len(ids) < 1 {
+			return errors.New("missing status IDs")
+		}
+		var report *madon.Report
+		report, err = gClient.ReportUser(opt.accountID, ids, opt.comment)
+		obj = report
+	default:
+		return errors.New("accountSubcommand: internal error")
+	}
+
+	if err != nil {
+		errPrint("Error: %s", err.Error())
+		return nil
+	}
+	if obj == nil {
+		return nil
+	}
+
+	p, err := getPrinter()
+	if err != nil {
+		return err
+	}
+	return p.PrintObj(obj, nil, "")
+}