add support for creating a status with a poll

This commit is contained in:
Dan Anglin 2024-06-15 01:57:10 +01:00
parent b06e92f26b
commit f66e34cd49
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
6 changed files with 153 additions and 78 deletions

View file

@ -38,10 +38,18 @@ type CreateStatusForm struct {
Likeable bool `json:"likeable"`
Replyable bool `json:"replyable"`
Sensitive bool `json:"sensitive"`
Poll *CreateStatusPollForm `json:"poll,omitempty"`
ContentType model.StatusContentType `json:"content_type"`
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) {
data, err := json.Marshal(form)
if err != nil {

View file

@ -21,8 +21,8 @@ type AddExecutor struct {
listID string
statusID string
pollID string
choices PollChoices
accountNames AccountNames
choices MultiIntFlagValue
accountNames MultiStringFlagValue
content string
}
@ -31,7 +31,7 @@ func NewAddExecutor(tlf TopLevelFlags, name, summary string) *AddExecutor {
addExe := AddExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountNames: AccountNames(emptyArr),
accountNames: MultiStringFlagValue(emptyArr),
topLevelFlags: tlf,
}
@ -265,7 +265,7 @@ func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
}
if poll.Expired {
return ExpiredPollError{}
return PollClosedError{}
}
if !poll.Multiple && len(a.choices) > 1 {

View file

@ -18,20 +18,25 @@ type CreateExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
addPoll bool
boostable bool
federated bool
likeable bool
pollAllowMultipleChoices bool
pollHideVoteCounts bool
replyable bool
sensitive *bool
content string
contentType string
fromFile string
language string
spoilerText string
resourceType string
listTitle string
listRepliesPolicy string
spoilerText string
visibility string
pollExpiresIn TimeDurationFlagValue
pollOptions MultiStringFlagValue
}
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.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.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.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")
@ -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.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.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 {
boolVal, err := strconv.ParseBool(value)
@ -189,6 +199,22 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
Replyable: c.replyable,
Sensitive: sensitive,
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)

View file

@ -32,7 +32,11 @@ type UnsupportedAddOperationError struct {
}
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 {
@ -41,7 +45,11 @@ type UnsupportedRemoveOperationError struct {
}
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 {
@ -67,10 +75,10 @@ func (e UnknownCommandError) Error() string {
return "unknown command '" + e.Command + "'"
}
type ExpiredPollError struct{}
type PollClosedError struct{}
func (e ExpiredPollError) Error() string {
return "this poll has expired"
func (e PollClosedError) Error() string {
return "this poll is closed"
}
type MultipleChoiceError struct{}
@ -78,3 +86,11 @@ type MultipleChoiceError struct{}
func (e MultipleChoiceError) Error() string {
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"
}

View file

@ -8,9 +8,11 @@ import (
"fmt"
"strconv"
"strings"
"time"
)
const (
flagAddPoll = "add-poll"
flagAccountName = "account-name"
flagBrowser = "browser"
flagChoose = "choose"
@ -31,7 +33,11 @@ const (
flagListRepliesPolicy = "list-replies-policy"
flagMyAccount = "my-account"
flagNotify = "notify"
flagPollAllowsMultipleChoices = "poll-allows-multiple-choices"
flagPollExpiresIn = "poll-expires-in"
flagPollHidesVoteCounts = "poll-hides-vote-counts"
flagPollID = "poll-id"
flagPollOption = "poll-option"
flagSensitive = "sensitive"
flagSkipRelationship = "skip-relationship"
flagShowPreferences = "show-preferences"
@ -45,33 +51,33 @@ const (
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 {
ConfigDir string
NoColor *bool
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: "
for ind, vote := range *p {
if ind == len(*p)-1 {
for ind, vote := range *v {
if ind == len(*v)-1 {
value += strconv.Itoa(vote)
} else {
value += strconv.Itoa(vote) + ", "
@ -81,13 +87,32 @@ func (p *PollChoices) String() string {
return value
}
func (p *PollChoices) Set(text string) error {
func (v *MultiIntFlagValue) Set(text string) error {
value, err := strconv.Atoi(text)
if err != nil {
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
}

View file

@ -19,7 +19,7 @@ type RemoveExecutor struct {
fromResourceType string
listID string
statusID string
accountNames AccountNames
accountNames MultiStringFlagValue
}
func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor {
@ -27,7 +27,7 @@ func NewRemoveExecutor(tlf TopLevelFlags, name, summary string) *RemoveExecutor
removeExe := RemoveExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountNames: AccountNames(emptyArr),
accountNames: MultiStringFlagValue(emptyArr),
topLevelFlags: tlf,
}