cmd/accounts.go
changeset 0 5abace724584
child 6 5228e517c455
equal deleted inserted replaced
-1:000000000000 0:5abace724584
       
     1 // Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
       
     2 //
       
     3 // Licensed under the MIT license.
       
     4 // Please see the LICENSE file is this directory.
       
     5 
       
     6 package cmd
       
     7 
       
     8 import (
       
     9 	"errors"
       
    10 	"strings"
       
    11 
       
    12 	"github.com/spf13/cobra"
       
    13 
       
    14 	"github.com/McKael/madon"
       
    15 )
       
    16 
       
    17 var accountsOpts struct {
       
    18 	accountID                 int
       
    19 	unset                     bool // TODO remove eventually?
       
    20 	limit                     int
       
    21 	onlyMedia, excludeReplies bool   // For acccount statuses
       
    22 	remoteUID                 string // For account follow
       
    23 	acceptFR, rejectFR        bool   // For account follow_requests
       
    24 	list                      bool   // For account follow_requests/reports
       
    25 	accountIDs                string // For account relationships
       
    26 	statusIDs                 string // For account reports
       
    27 	comment                   string // For account reports
       
    28 	show                      bool   // For account reports
       
    29 }
       
    30 
       
    31 func init() {
       
    32 	RootCmd.AddCommand(accountsCmd)
       
    33 
       
    34 	// Subcommands
       
    35 	accountsCmd.AddCommand(accountSubcommands...)
       
    36 
       
    37 	// Global flags
       
    38 	accountsCmd.PersistentFlags().IntVarP(&accountsOpts.accountID, "account-id", "a", 0, "Account ID number")
       
    39 	//accountsCmd.PersistentFlags().IntVarP(&accountsOpts.limit, "limit", "l", 0, "Limit number of results")
       
    40 
       
    41 	// Subcommand flags
       
    42 	accountStatusesSubcommand.Flags().BoolVar(&accountsOpts.onlyMedia, "only-media", false, "Only statuses with media attachments")
       
    43 	accountStatusesSubcommand.Flags().BoolVar(&accountsOpts.excludeReplies, "exclude-replies", false, "Exclude replies to other statuses")
       
    44 
       
    45 	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.list, "list", false, "List pending follow requests")
       
    46 	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.acceptFR, "accept", false, "Accept the follow request from the account ID")
       
    47 	accountFollowRequestsSubcommand.Flags().BoolVar(&accountsOpts.rejectFR, "reject", false, "Reject the follow request from the account ID")
       
    48 
       
    49 	accountBlockSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unblock the account")
       
    50 	accountMuteSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unmute the account")
       
    51 	accountFollowSubcommand.Flags().BoolVarP(&accountsOpts.unset, "unset", "", false, "Unfollow the account")
       
    52 	accountFollowSubcommand.Flags().StringVarP(&accountsOpts.remoteUID, "remote", "r", "", "Follow remote account (user@domain)")
       
    53 
       
    54 	accountRelationshipsSubcommand.Flags().StringVar(&accountsOpts.accountIDs, "account-ids", "", "Comma-separated list of account IDs")
       
    55 
       
    56 	accountReportsSubcommand.Flags().StringVar(&accountsOpts.statusIDs, "status-ids", "", "Comma-separated list of status IDs")
       
    57 	accountReportsSubcommand.Flags().StringVar(&accountsOpts.comment, "comment", "", "Report comment")
       
    58 	accountReportsSubcommand.Flags().BoolVar(&accountsOpts.list, "list", false, "List current user reports")
       
    59 }
       
    60 
       
    61 // accountsCmd represents the accounts command
       
    62 // This command does nothing without a subcommand
       
    63 var accountsCmd = &cobra.Command{
       
    64 	Use:     "accounts [--account-id ID] subcommand",
       
    65 	Aliases: []string{"account"},
       
    66 	Short:   "Account-related functions",
       
    67 	//Long:    `TBW...`, // TODO
       
    68 	//PersistentPreRunE: func(cmd *cobra.Command, args []string) error {},
       
    69 }
       
    70 
       
    71 // Note: Some account subcommands are not defined in this file.
       
    72 var accountSubcommands = []*cobra.Command{
       
    73 	&cobra.Command{
       
    74 		Use: "show",
       
    75 		Long: `Displays the details about the requested account.
       
    76 If no account ID is specified, the current user account is used.`,
       
    77 		Aliases: []string{"display"},
       
    78 		Short:   "Display the account",
       
    79 		RunE: func(cmd *cobra.Command, args []string) error {
       
    80 			return accountSubcommandsRunE(cmd.Name(), args)
       
    81 		},
       
    82 	},
       
    83 	&cobra.Command{
       
    84 		Use:   "followers",
       
    85 		Short: "Display the accounts following the specified account",
       
    86 		RunE: func(cmd *cobra.Command, args []string) error {
       
    87 			return accountSubcommandsRunE(cmd.Name(), args)
       
    88 		},
       
    89 	},
       
    90 	&cobra.Command{
       
    91 		Use:   "following",
       
    92 		Short: "Display the accounts followed by the specified account",
       
    93 		RunE: func(cmd *cobra.Command, args []string) error {
       
    94 			return accountSubcommandsRunE(cmd.Name(), args)
       
    95 		},
       
    96 	},
       
    97 	&cobra.Command{
       
    98 		Use:     "favourites",
       
    99 		Aliases: []string{"favorites", "favourited", "favorited"},
       
   100 		Short:   "Display the user's favourites",
       
   101 		RunE: func(cmd *cobra.Command, args []string) error {
       
   102 			return accountSubcommandsRunE(cmd.Name(), args)
       
   103 		},
       
   104 	},
       
   105 	&cobra.Command{
       
   106 		Use:     "blocks",
       
   107 		Aliases: []string{"blocked"},
       
   108 		Short:   "Display the user's blocked accounts",
       
   109 		RunE: func(cmd *cobra.Command, args []string) error {
       
   110 			return accountSubcommandsRunE(cmd.Name(), args)
       
   111 		},
       
   112 	},
       
   113 	&cobra.Command{
       
   114 		Use:     "mutes",
       
   115 		Aliases: []string{"muted"},
       
   116 		Short:   "Display the user's muted accounts",
       
   117 		RunE: func(cmd *cobra.Command, args []string) error {
       
   118 			return accountSubcommandsRunE(cmd.Name(), args)
       
   119 		},
       
   120 	},
       
   121 	&cobra.Command{
       
   122 		Use:   "search TEXT",
       
   123 		Short: "Search for user accounts",
       
   124 		Long: `Search for user accounts.
       
   125 The server will lookup an account remotely if the search term is in the
       
   126 username@domain format and not yet in the database.`,
       
   127 		RunE: func(cmd *cobra.Command, args []string) error {
       
   128 			return accountSubcommandsRunE(cmd.Name(), args)
       
   129 		},
       
   130 	},
       
   131 	accountStatusesSubcommand,
       
   132 	accountFollowRequestsSubcommand,
       
   133 	accountFollowSubcommand,
       
   134 	accountBlockSubcommand,
       
   135 	accountMuteSubcommand,
       
   136 	accountRelationshipsSubcommand,
       
   137 	accountReportsSubcommand,
       
   138 }
       
   139 
       
   140 var accountStatusesSubcommand = &cobra.Command{
       
   141 	Use:     "statuses",
       
   142 	Aliases: []string{"st"},
       
   143 	Short:   "Display the account statuses",
       
   144 	RunE: func(cmd *cobra.Command, args []string) error {
       
   145 		return accountSubcommandsRunE(cmd.Name(), args)
       
   146 	},
       
   147 }
       
   148 
       
   149 var accountFollowRequestsSubcommand = &cobra.Command{
       
   150 	Use:     "follow-requests",
       
   151 	Aliases: []string{"follow-request", "fr"},
       
   152 	Example: `  madonctl accounts follow-requests --list
       
   153   madonctl accounts follow-requests --account-id X --accept
       
   154   madonctl accounts follow-requests --account-id Y --reject`,
       
   155 	Short: "List, accept or deny a follow request",
       
   156 	RunE: func(cmd *cobra.Command, args []string) error {
       
   157 		return accountSubcommandsRunE("follow-requests", args)
       
   158 	},
       
   159 }
       
   160 var accountFollowSubcommand = &cobra.Command{
       
   161 	Use:   "follow",
       
   162 	Short: "Follow or unfollow the account",
       
   163 	RunE: func(cmd *cobra.Command, args []string) error {
       
   164 		return accountSubcommandsRunE("follow", args)
       
   165 	},
       
   166 }
       
   167 
       
   168 var accountBlockSubcommand = &cobra.Command{
       
   169 	Use:   "block",
       
   170 	Short: "Block or unblock the account",
       
   171 	RunE: func(cmd *cobra.Command, args []string) error {
       
   172 		return accountSubcommandsRunE("block", args)
       
   173 	},
       
   174 }
       
   175 
       
   176 var accountMuteSubcommand = &cobra.Command{
       
   177 	Use:   "mute",
       
   178 	Short: "Mute or unmute the account",
       
   179 	RunE: func(cmd *cobra.Command, args []string) error {
       
   180 		return accountSubcommandsRunE("mute", args)
       
   181 	},
       
   182 }
       
   183 
       
   184 var accountRelationshipsSubcommand = &cobra.Command{
       
   185 	Use:   "relationships --account-ids ACC1,ACC2...",
       
   186 	Short: "List relationships with the accounts",
       
   187 	RunE: func(cmd *cobra.Command, args []string) error {
       
   188 		return accountSubcommandsRunE("relationships", args)
       
   189 	},
       
   190 }
       
   191 
       
   192 var accountReportsSubcommand = &cobra.Command{
       
   193 	Use:   "reports",
       
   194 	Short: "List reports or report a user account",
       
   195 	Example: `  madonctl accounts reports --list
       
   196   madonctl accounts reports --account-id ACCOUNT --status-ids ID... --comment TEXT`,
       
   197 	RunE: func(cmd *cobra.Command, args []string) error {
       
   198 		return accountSubcommandsRunE("reports", args)
       
   199 	},
       
   200 }
       
   201 
       
   202 // accountSubcommandsRunE is a generic function for status subcommands
       
   203 func accountSubcommandsRunE(subcmd string, args []string) error {
       
   204 	opt := accountsOpts
       
   205 
       
   206 	switch subcmd {
       
   207 	case "show", "search":
       
   208 		// These subcommands do not require an account ID
       
   209 	case "favourites", "blocks", "mutes":
       
   210 		// Those subcommands can not use an account ID
       
   211 		if opt.accountID > 0 {
       
   212 			return errors.New("useless account ID")
       
   213 		}
       
   214 	case "follow":
       
   215 		if opt.accountID < 1 && opt.remoteUID == "" {
       
   216 			return errors.New("missing account ID or URI")
       
   217 		}
       
   218 		if opt.accountID > 0 && opt.remoteUID != "" {
       
   219 			return errors.New("cannot use both account ID and URI")
       
   220 		}
       
   221 		if opt.unset && opt.accountID < 1 {
       
   222 			return errors.New("unfollowing requires an account ID")
       
   223 		}
       
   224 	case "follow-requests":
       
   225 		if opt.list {
       
   226 			if opt.acceptFR || opt.rejectFR {
       
   227 				return errors.New("incompatible options")
       
   228 			}
       
   229 		} else {
       
   230 			if !opt.acceptFR && !opt.rejectFR { // No flag
       
   231 				return errors.New("missing parameter (--list, --accept or --reject)")
       
   232 			}
       
   233 			// This is a FR reply
       
   234 			if opt.acceptFR && opt.rejectFR {
       
   235 				return errors.New("incompatible options")
       
   236 			}
       
   237 			if opt.accountID < 1 {
       
   238 				return errors.New("missing account ID")
       
   239 			}
       
   240 		}
       
   241 	case "relationships":
       
   242 		if opt.accountID < 1 && len(opt.accountIDs) == 0 {
       
   243 			return errors.New("missing account IDs")
       
   244 		}
       
   245 		if opt.accountID > 0 && len(opt.accountIDs) > 0 {
       
   246 			return errors.New("incompatible options")
       
   247 		}
       
   248 	case "reports":
       
   249 		if opt.list {
       
   250 			break // No argument needed
       
   251 		}
       
   252 		if opt.accountID < 1 || len(opt.statusIDs) == 0 || opt.comment == "" {
       
   253 			return errors.New("missing parameter")
       
   254 		}
       
   255 	default:
       
   256 		// The other subcommands here require an account ID
       
   257 		if opt.accountID < 1 {
       
   258 			return errors.New("missing account ID")
       
   259 		}
       
   260 	}
       
   261 
       
   262 	// All account subcommands need to have signed in
       
   263 	if err := madonInit(true); err != nil {
       
   264 		return err
       
   265 	}
       
   266 
       
   267 	var obj interface{}
       
   268 	var err error
       
   269 
       
   270 	switch subcmd {
       
   271 	case "show":
       
   272 		var account *madon.Account
       
   273 		if opt.accountID > 0 {
       
   274 			account, err = gClient.GetAccount(opt.accountID)
       
   275 		} else {
       
   276 			account, err = gClient.GetCurrentAccount()
       
   277 		}
       
   278 		obj = account
       
   279 	case "search":
       
   280 		var accountList []madon.Account
       
   281 		limit := 0 // TODO use a global flag
       
   282 		accountList, err = gClient.SearchAccounts(strings.Join(args, " "), limit)
       
   283 		obj = accountList
       
   284 	case "followers":
       
   285 		var accountList []madon.Account
       
   286 		accountList, err = gClient.GetAccountFollowers(opt.accountID)
       
   287 		obj = accountList
       
   288 	case "following":
       
   289 		var accountList []madon.Account
       
   290 		accountList, err = gClient.GetAccountFollowing(opt.accountID)
       
   291 		obj = accountList
       
   292 	case "statuses":
       
   293 		var statusList []madon.Status
       
   294 		statusList, err = gClient.GetAccountStatuses(opt.accountID, opt.onlyMedia, opt.excludeReplies)
       
   295 		obj = statusList
       
   296 	case "follow":
       
   297 		if opt.unset {
       
   298 			err = gClient.UnfollowAccount(opt.accountID)
       
   299 		} else {
       
   300 			if opt.accountID > 0 {
       
   301 				err = gClient.FollowAccount(opt.accountID)
       
   302 			} else {
       
   303 				var account *madon.Account
       
   304 				account, err = gClient.FollowRemoteAccount(opt.remoteUID)
       
   305 				obj = account
       
   306 			}
       
   307 		}
       
   308 	case "follow-requests":
       
   309 		if opt.list {
       
   310 			var followRequests []madon.Account
       
   311 			followRequests, err = gClient.GetAccountFollowRequests()
       
   312 			obj = followRequests
       
   313 		} else {
       
   314 			err = gClient.FollowRequestAuthorize(opt.accountID, !opt.rejectFR)
       
   315 		}
       
   316 	case "block":
       
   317 		if opt.unset {
       
   318 			err = gClient.UnblockAccount(opt.accountID)
       
   319 		} else {
       
   320 			err = gClient.BlockAccount(opt.accountID)
       
   321 		}
       
   322 	case "mute":
       
   323 		if opt.unset {
       
   324 			err = gClient.UnmuteAccount(opt.accountID)
       
   325 		} else {
       
   326 			err = gClient.MuteAccount(opt.accountID)
       
   327 		}
       
   328 	case "favourites":
       
   329 		var statusList []madon.Status
       
   330 		statusList, err = gClient.GetFavourites()
       
   331 		obj = statusList
       
   332 	case "blocks":
       
   333 		var accountList []madon.Account
       
   334 		accountList, err = gClient.GetBlockedAccounts()
       
   335 		obj = accountList
       
   336 	case "mutes":
       
   337 		var accountList []madon.Account
       
   338 		accountList, err = gClient.GetMutedAccounts()
       
   339 		obj = accountList
       
   340 	case "relationships":
       
   341 		var ids []int
       
   342 		ids, err = splitIDs(opt.accountIDs)
       
   343 		if err != nil {
       
   344 			return errors.New("cannot parse account IDs")
       
   345 		}
       
   346 		if opt.accountID > 0 { // Allow --account-id
       
   347 			ids = []int{opt.accountID}
       
   348 		}
       
   349 		if len(ids) < 1 {
       
   350 			return errors.New("missing account IDs")
       
   351 		}
       
   352 		var relationships []madon.Relationship
       
   353 		relationships, err = gClient.GetAccountRelationships(ids)
       
   354 		obj = relationships
       
   355 	case "reports":
       
   356 		if opt.list {
       
   357 			var reports []madon.Report
       
   358 			reports, err = gClient.GetReports()
       
   359 			obj = reports
       
   360 			break
       
   361 		}
       
   362 		// Send a report
       
   363 		var ids []int
       
   364 		ids, err = splitIDs(opt.statusIDs)
       
   365 		if err != nil {
       
   366 			return errors.New("cannot parse status IDs")
       
   367 		}
       
   368 		if len(ids) < 1 {
       
   369 			return errors.New("missing status IDs")
       
   370 		}
       
   371 		var report *madon.Report
       
   372 		report, err = gClient.ReportUser(opt.accountID, ids, opt.comment)
       
   373 		obj = report
       
   374 	default:
       
   375 		return errors.New("accountSubcommand: internal error")
       
   376 	}
       
   377 
       
   378 	if err != nil {
       
   379 		errPrint("Error: %s", err.Error())
       
   380 		return nil
       
   381 	}
       
   382 	if obj == nil {
       
   383 		return nil
       
   384 	}
       
   385 
       
   386 	p, err := getPrinter()
       
   387 	if err != nil {
       
   388 		return err
       
   389 	}
       
   390 	return p.PrintObj(obj, nil, "")
       
   391 }