From ac481925622df9bf8024d1b5726282d0214fd22b Mon Sep 17 00:00:00 2001 From: kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:47:07 +0000 Subject: [bugfix] poll vote count fixes (#2444) * don't drop all vote counts if hideCounts is set, refactors poll option extraction slightly * omit voters_count when not set * make voters_count a ptr to ensure it is omit unless definitely needed * handle case of expires_at, voters_count and option.votes_count being nilable * faster isNil check * remove omitempty tags since mastodon API marks things as nullable but still sets them in outgoing json --- internal/ap/extract.go | 78 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 26 deletions(-) (limited to 'internal/ap') diff --git a/internal/ap/extract.go b/internal/ap/extract.go index 987ff5e55..11c20494c 100644 --- a/internal/ap/extract.go +++ b/internal/ap/extract.go @@ -1102,19 +1102,11 @@ func ExtractPoll(poll Pollable) (*gtsmodel.Poll, error) { var closed time.Time // Extract the options (votes if any) and 'multiple choice' flag. - options, votes, multi, err := ExtractPollOptions(poll) + options, multi, hideCounts, err := extractPollOptions(poll) if err != nil { return nil, err } - // Check if counts have been hidden from us. - hideCounts := len(options) != len(votes) - - if hideCounts { - // Simply provide zeroed slice. - votes = make([]int, len(options)) - } - // Extract the poll closed time, // it's okay for this to be zero. closedSlice := GetClosed(poll) @@ -1138,53 +1130,87 @@ func ExtractPoll(poll Pollable) (*gtsmodel.Poll, error) { voters := GetVotersCount(poll) return >smodel.Poll{ - Options: options, + Options: optionNames(options), Multiple: &multi, HideCounts: &hideCounts, - Votes: votes, + Votes: optionVotes(options), Voters: &voters, ExpiresAt: endTime, ClosedAt: closed, }, nil } -// ExtractPollOptions extracts poll option name strings, and the 'multiple choice flag' property value from Pollable. -func ExtractPollOptions(poll Pollable) (names []string, votes []int, multi bool, err error) { +// pollOption is a simple type +// to unify a poll option name +// with the number of votes. +type pollOption struct { + Name string + Votes int +} + +// optionNames extracts name strings from a slice of poll options. +func optionNames(in []pollOption) []string { + out := make([]string, len(in)) + for i := range in { + out[i] = in[i].Name + } + return out +} + +// optionVotes extracts vote counts from a slice of poll options. +func optionVotes(in []pollOption) []int { + out := make([]int, len(in)) + for i := range in { + out[i] = in[i].Votes + } + return out +} + +// extractPollOptions extracts poll option name strings, the 'multiple choice flag', and 'hideCounts' intrinsic flag properties value from Pollable. +func extractPollOptions(poll Pollable) (options []pollOption, multi bool, hide bool, err error) { var errs gtserror.MultiError // Iterate the oneOf property and gather poll single-choice options. IterateOneOf(poll, func(iter vocab.ActivityStreamsOneOfPropertyIterator) { - name, count, err := extractPollOption(iter.GetType()) + name, votes, err := extractPollOption(iter.GetType()) if err != nil { errs.Append(err) return } - names = append(names, name) - if count != nil { - votes = append(votes, *count) + if votes == nil { + hide = true + votes = new(int) } + options = append(options, pollOption{ + Name: name, + Votes: *votes, + }) }) - if len(names) > 0 || len(errs) > 0 { - return names, votes, false, errs.Combine() + if len(options) > 0 || len(errs) > 0 { + return options, false, hide, errs.Combine() } // Iterate the anyOf property and gather poll multi-choice options. IterateAnyOf(poll, func(iter vocab.ActivityStreamsAnyOfPropertyIterator) { - name, count, err := extractPollOption(iter.GetType()) + name, votes, err := extractPollOption(iter.GetType()) if err != nil { errs.Append(err) return } - names = append(names, name) - if count != nil { - votes = append(votes, *count) + if votes == nil { + hide = true + votes = new(int) } + options = append(options, pollOption{ + Name: name, + Votes: *votes, + }) }) - if len(names) > 0 || len(errs) > 0 { - return names, votes, true, errs.Combine() + if len(options) > 0 || len(errs) > 0 { + return options, true, hide, errs.Combine() } - return nil, nil, false, errors.New("poll without options") + return nil, false, false, errors.New("poll without options") } // IterateOneOf will attempt to extract oneOf property from given interface, and passes each iterated item to function. -- cgit v1.2.3