add support for creating a status with a poll
This commit is contained in:
parent
b06e92f26b
commit
f66e34cd49
6 changed files with 153 additions and 78 deletions
|
@ -38,10 +38,18 @@ type CreateStatusForm struct {
|
||||||
Likeable bool `json:"likeable"`
|
Likeable bool `json:"likeable"`
|
||||||
Replyable bool `json:"replyable"`
|
Replyable bool `json:"replyable"`
|
||||||
Sensitive bool `json:"sensitive"`
|
Sensitive bool `json:"sensitive"`
|
||||||
|
Poll *CreateStatusPollForm `json:"poll,omitempty"`
|
||||||
ContentType model.StatusContentType `json:"content_type"`
|
ContentType model.StatusContentType `json:"content_type"`
|
||||||
Visibility model.StatusVisibility `json:"visibility"`
|
Visibility model.StatusVisibility `json:"visibility"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateStatusPollForm struct {
|
||||||
|
Options []string `json:"options"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
Multiple bool `json:"multiple"`
|
||||||
|
HideTotals bool `json:"hide_totals"`
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Client) CreateStatus(form CreateStatusForm) (model.Status, error) {
|
func (g *Client) CreateStatus(form CreateStatusForm) (model.Status, error) {
|
||||||
data, err := json.Marshal(form)
|
data, err := json.Marshal(form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,8 +21,8 @@ type AddExecutor struct {
|
||||||
listID string
|
listID string
|
||||||
statusID string
|
statusID string
|
||||||
pollID string
|
pollID string
|
||||||
choices PollChoices
|
choices MultiIntFlagValue
|
||||||
accountNames AccountNames
|
accountNames MultiStringFlagValue
|
||||||
content string
|
content string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func NewAddExecutor(tlf TopLevelFlags, name, summary string) *AddExecutor {
|
||||||
|
|
||||||
addExe := AddExecutor{
|
addExe := AddExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
accountNames: AccountNames(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
topLevelFlags: tlf,
|
topLevelFlags: tlf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if poll.Expired {
|
if poll.Expired {
|
||||||
return ExpiredPollError{}
|
return PollClosedError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !poll.Multiple && len(a.choices) > 1 {
|
if !poll.Multiple && len(a.choices) > 1 {
|
||||||
|
|
|
@ -17,21 +17,26 @@ import (
|
||||||
type CreateExecutor struct {
|
type CreateExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
|
||||||
topLevelFlags TopLevelFlags
|
topLevelFlags TopLevelFlags
|
||||||
boostable bool
|
addPoll bool
|
||||||
federated bool
|
boostable bool
|
||||||
likeable bool
|
federated bool
|
||||||
replyable bool
|
likeable bool
|
||||||
sensitive *bool
|
pollAllowMultipleChoices bool
|
||||||
content string
|
pollHideVoteCounts bool
|
||||||
contentType string
|
replyable bool
|
||||||
fromFile string
|
sensitive *bool
|
||||||
language string
|
content string
|
||||||
spoilerText string
|
contentType string
|
||||||
resourceType string
|
fromFile string
|
||||||
listTitle string
|
language string
|
||||||
listRepliesPolicy string
|
resourceType string
|
||||||
visibility string
|
listTitle string
|
||||||
|
listRepliesPolicy string
|
||||||
|
spoilerText string
|
||||||
|
visibility string
|
||||||
|
pollExpiresIn TimeDurationFlagValue
|
||||||
|
pollOptions MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor {
|
func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor {
|
||||||
|
@ -45,6 +50,9 @@ func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor
|
||||||
createExe.BoolVar(&createExe.federated, flagEnableFederation, true, "Specify if the status can be federated beyond the local timelines")
|
createExe.BoolVar(&createExe.federated, flagEnableFederation, true, "Specify if the status can be federated beyond the local timelines")
|
||||||
createExe.BoolVar(&createExe.likeable, flagEnableLikes, true, "Specify if the status can be liked/favourited")
|
createExe.BoolVar(&createExe.likeable, flagEnableLikes, true, "Specify if the status can be liked/favourited")
|
||||||
createExe.BoolVar(&createExe.replyable, flagEnableReplies, true, "Specify if the status can be replied to")
|
createExe.BoolVar(&createExe.replyable, flagEnableReplies, true, "Specify if the status can be replied to")
|
||||||
|
createExe.BoolVar(&createExe.pollAllowMultipleChoices, flagPollAllowsMultipleChoices, false, "The poll allows viewers to make multiple choices in the poll")
|
||||||
|
createExe.BoolVar(&createExe.pollHideVoteCounts, flagPollHidesVoteCounts, false, "The poll will hide the vote count until it is closed")
|
||||||
|
createExe.BoolVar(&createExe.addPoll, flagAddPoll, false, "Add a poll to the status")
|
||||||
createExe.StringVar(&createExe.content, flagContent, "", "The content of the status to create")
|
createExe.StringVar(&createExe.content, flagContent, "", "The content of the status to create")
|
||||||
createExe.StringVar(&createExe.contentType, flagContentType, "plain", "The type that the contents should be parsed from (valid values are plain and markdown)")
|
createExe.StringVar(&createExe.contentType, flagContentType, "plain", "The type that the contents should be parsed from (valid values are plain and markdown)")
|
||||||
createExe.StringVar(&createExe.fromFile, flagFromFile, "", "The file path where to read the contents from")
|
createExe.StringVar(&createExe.fromFile, flagFromFile, "", "The file path where to read the contents from")
|
||||||
|
@ -54,6 +62,8 @@ func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor
|
||||||
createExe.StringVar(&createExe.resourceType, flagType, "", "Specify the type of resource to create")
|
createExe.StringVar(&createExe.resourceType, flagType, "", "Specify the type of resource to create")
|
||||||
createExe.StringVar(&createExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
createExe.StringVar(&createExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
||||||
createExe.StringVar(&createExe.listRepliesPolicy, flagListRepliesPolicy, "list", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
createExe.StringVar(&createExe.listRepliesPolicy, flagListRepliesPolicy, "list", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
||||||
|
createExe.Var(&createExe.pollOptions, flagPollOption, "A poll option. Use this multiple times to set multiple options")
|
||||||
|
createExe.Var(&createExe.pollExpiresIn, flagPollExpiresIn, "The duration in which the poll is open for")
|
||||||
|
|
||||||
createExe.BoolFunc(flagSensitive, "Specify if the status should be marked as sensitive", func(value string) error {
|
createExe.BoolFunc(flagSensitive, "Specify if the status should be marked as sensitive", func(value string) error {
|
||||||
boolVal, err := strconv.ParseBool(value)
|
boolVal, err := strconv.ParseBool(value)
|
||||||
|
@ -189,6 +199,22 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
||||||
Replyable: c.replyable,
|
Replyable: c.replyable,
|
||||||
Sensitive: sensitive,
|
Sensitive: sensitive,
|
||||||
Visibility: parsedVisibility,
|
Visibility: parsedVisibility,
|
||||||
|
Poll: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.addPoll {
|
||||||
|
if len(c.pollOptions) == 0 {
|
||||||
|
return NoPollOptionError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
poll := client.CreateStatusPollForm{
|
||||||
|
Options: c.pollOptions,
|
||||||
|
Multiple: c.pollAllowMultipleChoices,
|
||||||
|
HideTotals: c.pollHideVoteCounts,
|
||||||
|
ExpiresIn: int(c.pollExpiresIn.Duration.Seconds()),
|
||||||
|
}
|
||||||
|
|
||||||
|
form.Poll = &poll
|
||||||
}
|
}
|
||||||
|
|
||||||
status, err := gtsClient.CreateStatus(form)
|
status, err := gtsClient.CreateStatus(form)
|
||||||
|
|
|
@ -32,7 +32,11 @@ type UnsupportedAddOperationError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e UnsupportedAddOperationError) Error() string {
|
func (e UnsupportedAddOperationError) Error() string {
|
||||||
return "adding '" + e.ResourceType + "' to '" + e.AddToResourceType + "' is not supported"
|
return "adding '" +
|
||||||
|
e.ResourceType +
|
||||||
|
"' to '" +
|
||||||
|
e.AddToResourceType +
|
||||||
|
"' is not supported"
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnsupportedRemoveOperationError struct {
|
type UnsupportedRemoveOperationError struct {
|
||||||
|
@ -41,7 +45,11 @@ type UnsupportedRemoveOperationError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e UnsupportedRemoveOperationError) Error() string {
|
func (e UnsupportedRemoveOperationError) Error() string {
|
||||||
return "removing '" + e.ResourceType + "' from '" + e.RemoveFromResourceType + "' is not supported"
|
return "removing '" +
|
||||||
|
e.ResourceType +
|
||||||
|
"' from '" +
|
||||||
|
e.RemoveFromResourceType +
|
||||||
|
"' is not supported"
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmptyContentError struct {
|
type EmptyContentError struct {
|
||||||
|
@ -67,10 +75,10 @@ func (e UnknownCommandError) Error() string {
|
||||||
return "unknown command '" + e.Command + "'"
|
return "unknown command '" + e.Command + "'"
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExpiredPollError struct{}
|
type PollClosedError struct{}
|
||||||
|
|
||||||
func (e ExpiredPollError) Error() string {
|
func (e PollClosedError) Error() string {
|
||||||
return "this poll has expired"
|
return "this poll is closed"
|
||||||
}
|
}
|
||||||
|
|
||||||
type MultipleChoiceError struct{}
|
type MultipleChoiceError struct{}
|
||||||
|
@ -78,3 +86,11 @@ type MultipleChoiceError struct{}
|
||||||
func (e MultipleChoiceError) Error() string {
|
func (e MultipleChoiceError) Error() string {
|
||||||
return "this poll does not allow multiple choices"
|
return "this poll does not allow multiple choices"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NoPollOptionError struct{}
|
||||||
|
|
||||||
|
func (e NoPollOptionError) Error() string {
|
||||||
|
return "no options were provided for this poll, please use the --" +
|
||||||
|
flagPollOption +
|
||||||
|
" flag to add options to the poll"
|
||||||
|
}
|
||||||
|
|
|
@ -8,70 +8,76 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
flagAccountName = "account-name"
|
flagAddPoll = "add-poll"
|
||||||
flagBrowser = "browser"
|
flagAccountName = "account-name"
|
||||||
flagChoose = "choose"
|
flagBrowser = "browser"
|
||||||
flagContentType = "content-type"
|
flagChoose = "choose"
|
||||||
flagContent = "content"
|
flagContentType = "content-type"
|
||||||
flagEnableFederation = "enable-federation"
|
flagContent = "content"
|
||||||
flagEnableLikes = "enable-likes"
|
flagEnableFederation = "enable-federation"
|
||||||
flagEnableReplies = "enable-replies"
|
flagEnableLikes = "enable-likes"
|
||||||
flagEnableReposts = "enable-reposts"
|
flagEnableReplies = "enable-replies"
|
||||||
flagFrom = "from"
|
flagEnableReposts = "enable-reposts"
|
||||||
flagFromFile = "from-file"
|
flagFrom = "from"
|
||||||
flagFull = "full"
|
flagFromFile = "from-file"
|
||||||
flagInstance = "instance"
|
flagFull = "full"
|
||||||
flagLanguage = "language"
|
flagInstance = "instance"
|
||||||
flagLimit = "limit"
|
flagLanguage = "language"
|
||||||
flagListID = "list-id"
|
flagLimit = "limit"
|
||||||
flagListTitle = "list-title"
|
flagListID = "list-id"
|
||||||
flagListRepliesPolicy = "list-replies-policy"
|
flagListTitle = "list-title"
|
||||||
flagMyAccount = "my-account"
|
flagListRepliesPolicy = "list-replies-policy"
|
||||||
flagNotify = "notify"
|
flagMyAccount = "my-account"
|
||||||
flagPollID = "poll-id"
|
flagNotify = "notify"
|
||||||
flagSensitive = "sensitive"
|
flagPollAllowsMultipleChoices = "poll-allows-multiple-choices"
|
||||||
flagSkipRelationship = "skip-relationship"
|
flagPollExpiresIn = "poll-expires-in"
|
||||||
flagShowPreferences = "show-preferences"
|
flagPollHidesVoteCounts = "poll-hides-vote-counts"
|
||||||
flagShowReposts = "show-reposts"
|
flagPollID = "poll-id"
|
||||||
flagSpoilerText = "spoiler-text"
|
flagPollOption = "poll-option"
|
||||||
flagStatusID = "status-id"
|
flagSensitive = "sensitive"
|
||||||
flagTag = "tag"
|
flagSkipRelationship = "skip-relationship"
|
||||||
flagTimelineCategory = "timeline-category"
|
flagShowPreferences = "show-preferences"
|
||||||
flagTo = "to"
|
flagShowReposts = "show-reposts"
|
||||||
flagType = "type"
|
flagSpoilerText = "spoiler-text"
|
||||||
flagVisibility = "visibility"
|
flagStatusID = "status-id"
|
||||||
|
flagTag = "tag"
|
||||||
|
flagTimelineCategory = "timeline-category"
|
||||||
|
flagTo = "to"
|
||||||
|
flagType = "type"
|
||||||
|
flagVisibility = "visibility"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AccountNames []string
|
|
||||||
|
|
||||||
func (a *AccountNames) String() string {
|
|
||||||
return strings.Join(*a, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AccountNames) Set(value string) error {
|
|
||||||
if len(value) > 0 {
|
|
||||||
*a = append(*a, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TopLevelFlags struct {
|
type TopLevelFlags struct {
|
||||||
ConfigDir string
|
ConfigDir string
|
||||||
NoColor *bool
|
NoColor *bool
|
||||||
Pager string
|
Pager string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PollChoices []int
|
type MultiStringFlagValue []string
|
||||||
|
|
||||||
func (p *PollChoices) String() string {
|
func (v *MultiStringFlagValue) String() string {
|
||||||
|
return strings.Join(*v, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MultiStringFlagValue) Set(value string) error {
|
||||||
|
if len(value) > 0 {
|
||||||
|
*v = append(*v, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type MultiIntFlagValue []int
|
||||||
|
|
||||||
|
func (v *MultiIntFlagValue) String() string {
|
||||||
value := "Choices: "
|
value := "Choices: "
|
||||||
|
|
||||||
for ind, vote := range *p {
|
for ind, vote := range *v {
|
||||||
if ind == len(*p)-1 {
|
if ind == len(*v)-1 {
|
||||||
value += strconv.Itoa(vote)
|
value += strconv.Itoa(vote)
|
||||||
} else {
|
} else {
|
||||||
value += strconv.Itoa(vote) + ", "
|
value += strconv.Itoa(vote) + ", "
|
||||||
|
@ -81,13 +87,32 @@ func (p *PollChoices) String() string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PollChoices) Set(text string) error {
|
func (v *MultiIntFlagValue) Set(text string) error {
|
||||||
value, err := strconv.Atoi(text)
|
value, err := strconv.Atoi(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse the value to an integer: %w", err)
|
return fmt.Errorf("unable to parse the value to an integer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = append(*p, value)
|
*v = append(*v, value)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeDurationFlagValue struct {
|
||||||
|
Duration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v TimeDurationFlagValue) String() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *TimeDurationFlagValue) Set(text string) error {
|
||||||
|
duration, err := time.ParseDuration(text)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to parse the value as time duration: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Duration = duration
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ type RemoveExecutor struct {
|
||||||
fromResourceType string
|
fromResourceType string
|
||||||
listID string
|
listID string
|
||||||
statusID string
|
statusID string
|
||||||
accountNames AccountNames
|
accountNames MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor {
|
func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor {
|
||||||
|
@ -27,7 +27,7 @@ func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor
|
||||||
|
|
||||||
removeExe := RemoveExecutor{
|
removeExe := RemoveExecutor{
|
||||||
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
|
||||||
accountNames: AccountNames(emptyArr),
|
accountNames: MultiStringFlagValue(emptyArr),
|
||||||
topLevelFlags: tlf,
|
topLevelFlags: tlf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue