mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 07:52:24 -05:00
[feature] support canceling scheduled tasks, some federation API performance improvements (#2329)
This commit is contained in:
parent
314dda196e
commit
41435a6c4e
23 changed files with 993 additions and 487 deletions
|
|
@ -91,6 +91,105 @@ func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeO
|
|||
}
|
||||
}
|
||||
|
||||
// ExtractAccountables extracts Accountable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
|
||||
func ExtractAccountables(arr []TypeOrIRI) ([]Accountable, []TypeOrIRI) {
|
||||
var accounts []Accountable
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
elem := arr[i]
|
||||
|
||||
if elem.IsIRI() {
|
||||
// skip IRIs
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract AS vocab type
|
||||
// associated with elem.
|
||||
t := elem.GetType()
|
||||
|
||||
// Try cast AS type as Accountable.
|
||||
account, ok := ToAccountable(t)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add casted accountable type.
|
||||
accounts = append(accounts, account)
|
||||
|
||||
// Drop elem from slice.
|
||||
copy(arr[:i], arr[i+1:])
|
||||
arr = arr[:len(arr)-1]
|
||||
}
|
||||
|
||||
return accounts, arr
|
||||
}
|
||||
|
||||
// ExtractStatusables extracts Statusable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
|
||||
func ExtractStatusables(arr []TypeOrIRI) ([]Statusable, []TypeOrIRI) {
|
||||
var statuses []Statusable
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
elem := arr[i]
|
||||
|
||||
if elem.IsIRI() {
|
||||
// skip IRIs
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract AS vocab type
|
||||
// associated with elem.
|
||||
t := elem.GetType()
|
||||
|
||||
// Try cast AS type as Statusable.
|
||||
status, ok := ToStatusable(t)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add casted Statusable type.
|
||||
statuses = append(statuses, status)
|
||||
|
||||
// Drop elem from slice.
|
||||
copy(arr[:i], arr[i+1:])
|
||||
arr = arr[:len(arr)-1]
|
||||
}
|
||||
|
||||
return statuses, arr
|
||||
}
|
||||
|
||||
// ExtractPollOptionables extracts PollOptionable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
|
||||
func ExtractPollOptionables(arr []TypeOrIRI) ([]PollOptionable, []TypeOrIRI) {
|
||||
var options []PollOptionable
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
elem := arr[i]
|
||||
|
||||
if elem.IsIRI() {
|
||||
// skip IRIs
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract AS vocab type
|
||||
// associated with elem.
|
||||
t := elem.GetType()
|
||||
|
||||
// Try cast as PollOptionable.
|
||||
option, ok := ToPollOptionable(t)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add casted PollOptionable type.
|
||||
options = append(options, option)
|
||||
|
||||
// Drop elem from slice.
|
||||
copy(arr[:i], arr[i+1:])
|
||||
arr = arr[:len(arr)-1]
|
||||
}
|
||||
|
||||
return options, arr
|
||||
}
|
||||
|
||||
// ExtractPreferredUsername returns a string representation of
|
||||
// an interface's preferredUsername property. Will return an
|
||||
// error if preferredUsername is nil, not a string, or empty.
|
||||
|
|
@ -192,7 +291,7 @@ func ExtractToURIs(i WithTo) []*url.URL {
|
|||
|
||||
// ExtractCcURIs returns a slice of URIs
|
||||
// that the given WithCC addresses as Cc.
|
||||
func ExtractCcURIs(i WithCC) []*url.URL {
|
||||
func ExtractCcURIs(i WithCc) []*url.URL {
|
||||
ccProp := i.GetActivityStreamsCc()
|
||||
if ccProp == nil {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -23,6 +23,21 @@ import (
|
|||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
)
|
||||
|
||||
// IsActivityable returns whether AS vocab type name is acceptable as Activityable.
|
||||
func IsActivityable(typeName string) bool {
|
||||
return isActivity(typeName) ||
|
||||
isIntransitiveActivity(typeName)
|
||||
}
|
||||
|
||||
// ToActivityable safely tries to cast vocab.Type as Activityable, also checking for expected AS type names.
|
||||
func ToActivityable(t vocab.Type) (Activityable, bool) {
|
||||
activityable, ok := t.(Activityable)
|
||||
if !ok || !IsActivityable(t.GetTypeName()) {
|
||||
return nil, false
|
||||
}
|
||||
return activityable, true
|
||||
}
|
||||
|
||||
// IsAccountable returns whether AS vocab type name is acceptable as Accountable.
|
||||
func IsAccountable(typeName string) bool {
|
||||
switch typeName {
|
||||
|
|
@ -88,6 +103,43 @@ func ToPollable(t vocab.Type) (Pollable, bool) {
|
|||
return pollable, true
|
||||
}
|
||||
|
||||
// IsPollOptionable returns whether AS vocab type name is acceptable as PollOptionable.
|
||||
func IsPollOptionable(typeName string) bool {
|
||||
return typeName == ObjectNote
|
||||
}
|
||||
|
||||
// ToPollOptionable safely tries to cast vocab.Type as PollOptionable, also checking for expected AS type names.
|
||||
func ToPollOptionable(t vocab.Type) (PollOptionable, bool) {
|
||||
note, ok := t.(vocab.ActivityStreamsNote)
|
||||
if !ok || !IsPollOptionable(t.GetTypeName()) {
|
||||
return nil, false
|
||||
}
|
||||
if note.GetActivityStreamsContent() != nil ||
|
||||
note.GetActivityStreamsName() == nil {
|
||||
// A PollOption is an ActivityStreamsNote
|
||||
// WITHOUT a content property, instead only
|
||||
// a name property.
|
||||
return nil, false
|
||||
}
|
||||
return note, true
|
||||
}
|
||||
|
||||
// Activityable represents the minimum activitypub interface for representing an 'activity'.
|
||||
// (see: IsActivityable() for types implementing this, though you MUST make sure to check
|
||||
// the typeName as this bare interface may be implementable by non-Activityable types).
|
||||
type Activityable interface {
|
||||
// Activity is also a vocab.Type
|
||||
vocab.Type
|
||||
|
||||
WithTo
|
||||
WithCc
|
||||
WithBcc
|
||||
WithAttributedTo
|
||||
WithActor
|
||||
WithObject
|
||||
WithPublished
|
||||
}
|
||||
|
||||
// Accountable represents the minimum activitypub interface for representing an 'account'.
|
||||
// (see: IsAccountable() for types implementing this, though you MUST make sure to check
|
||||
// the typeName as this bare interface may be implementable by non-Accountable types).
|
||||
|
|
@ -126,7 +178,7 @@ type Statusable interface {
|
|||
WithURL
|
||||
WithAttributedTo
|
||||
WithTo
|
||||
WithCC
|
||||
WithCc
|
||||
WithSensitive
|
||||
WithConversation
|
||||
WithContent
|
||||
|
|
@ -145,16 +197,21 @@ type Pollable interface {
|
|||
WithClosed
|
||||
WithVotersCount
|
||||
|
||||
// base-interface
|
||||
// base-interfaces
|
||||
Statusable
|
||||
}
|
||||
|
||||
// PollOptionable represents the minimum activitypub interface for representing a poll 'option'.
|
||||
// (see: IsPollOptionable() for types implementing this).
|
||||
// PollOptionable represents the minimum activitypub interface for representing a poll 'vote'.
|
||||
// (see: IsPollOptionable() for types implementing this, though you MUST make sure to check
|
||||
// the typeName as this bare interface may be implementable by non-Pollable types).
|
||||
type PollOptionable interface {
|
||||
WithTypeName
|
||||
vocab.Type
|
||||
|
||||
WithName
|
||||
WithTo
|
||||
WithInReplyTo
|
||||
WithReplies
|
||||
WithAttributedTo
|
||||
}
|
||||
|
||||
// Attachmentable represents the minimum activitypub interface for representing a 'mediaAttachment'. (see: IsAttachmentable).
|
||||
|
|
@ -226,13 +283,13 @@ type Announceable interface {
|
|||
WithObject
|
||||
WithPublished
|
||||
WithTo
|
||||
WithCC
|
||||
WithCc
|
||||
}
|
||||
|
||||
// Addressable represents the minimum interface for an addressed activity.
|
||||
type Addressable interface {
|
||||
WithTo
|
||||
WithCC
|
||||
WithCc
|
||||
}
|
||||
|
||||
// ReplyToable represents the minimum interface for an Activity that can be InReplyTo another activity.
|
||||
|
|
@ -268,6 +325,15 @@ type TypeOrIRI interface {
|
|||
WithType
|
||||
}
|
||||
|
||||
// Property represents the minimum interface for an ActivityStreams property with IRIs.
|
||||
type Property[T TypeOrIRI] interface {
|
||||
Len() int
|
||||
At(int) T
|
||||
|
||||
AppendIRI(*url.URL)
|
||||
SetIRI(int, *url.URL)
|
||||
}
|
||||
|
||||
// WithJSONLDId represents an activity with JSONLDIdProperty.
|
||||
type WithJSONLDId interface {
|
||||
GetJSONLDId() vocab.JSONLDIdProperty
|
||||
|
|
@ -386,18 +452,24 @@ type WithTo interface {
|
|||
SetActivityStreamsTo(vocab.ActivityStreamsToProperty)
|
||||
}
|
||||
|
||||
// WithCC represents an activity with ActivityStreamsCcProperty
|
||||
type WithCc interface {
|
||||
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
|
||||
SetActivityStreamsCc(vocab.ActivityStreamsCcProperty)
|
||||
}
|
||||
|
||||
// WithCC represents an activity with ActivityStreamsBccProperty
|
||||
type WithBcc interface {
|
||||
GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
|
||||
SetActivityStreamsBcc(vocab.ActivityStreamsBccProperty)
|
||||
}
|
||||
|
||||
// WithInReplyTo represents an activity with ActivityStreamsInReplyToProperty
|
||||
type WithInReplyTo interface {
|
||||
GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
|
||||
SetActivityStreamsInReplyTo(vocab.ActivityStreamsInReplyToProperty)
|
||||
}
|
||||
|
||||
// WithCC represents an activity with ActivityStreamsCcProperty
|
||||
type WithCC interface {
|
||||
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
|
||||
SetActivityStreamsCc(vocab.ActivityStreamsCcProperty)
|
||||
}
|
||||
|
||||
// WithSensitive represents an activity with ActivityStreamsSensitiveProperty
|
||||
type WithSensitive interface {
|
||||
GetActivityStreamsSensitive() vocab.ActivityStreamsSensitiveProperty
|
||||
|
|
|
|||
325
internal/ap/properties.go
Normal file
325
internal/ap/properties.go
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
)
|
||||
|
||||
// MustGet performs the given 'Get$Property(with) (T, error)' signature function, panicking on error.
|
||||
// func MustGet[W, T any](fn func(W) (T, error), with W) T {
|
||||
// t, err := fn(with)
|
||||
// if err != nil {
|
||||
// panicfAt(3, "error getting property on %T: %w", with, err)
|
||||
// }
|
||||
// return t
|
||||
// }
|
||||
|
||||
// MustSet performs the given 'Set$Property(with, T) error' signature function, panicking on error.
|
||||
// func MustSet[W, T any](fn func(W, T) error, with W, value T) {
|
||||
// err := fn(with, value)
|
||||
// if err != nil {
|
||||
// panicfAt(3, "error setting property on %T: %w", with, err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// AppendSet performs the given 'Append$Property(with, ...T) error' signature function, panicking on error.
|
||||
// func MustAppend[W, T any](fn func(W, ...T) error, with W, values ...T) {
|
||||
// err := fn(with, values...)
|
||||
// if err != nil {
|
||||
// panicfAt(3, "error appending properties on %T: %w", with, err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// GetJSONLDId returns the ID of 'with', or nil.
|
||||
func GetJSONLDId(with WithJSONLDId) *url.URL {
|
||||
idProp := with.GetJSONLDId()
|
||||
if idProp == nil {
|
||||
return nil
|
||||
}
|
||||
id := idProp.Get()
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the given URL to the JSONLD ID of 'with'.
|
||||
func SetJSONLDId(with WithJSONLDId, id *url.URL) {
|
||||
idProp := with.GetJSONLDId()
|
||||
if idProp == nil {
|
||||
idProp = streams.NewJSONLDIdProperty()
|
||||
}
|
||||
idProp.SetIRI(id)
|
||||
with.SetJSONLDId(idProp)
|
||||
}
|
||||
|
||||
// SetJSONLDIdStr sets the given string to the JSONLDID of 'with'. Returns error
|
||||
func SetJSONLDIdStr(with WithJSONLDId, id string) error {
|
||||
u, err := url.Parse(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing id url: %w", err)
|
||||
}
|
||||
SetJSONLDId(with, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTo returns the IRIs contained in the To property of 'with'. Panics on entries with missing ID.
|
||||
func GetTo(with WithTo) []*url.URL {
|
||||
toProp := with.GetActivityStreamsTo()
|
||||
return getIRIs[vocab.ActivityStreamsToPropertyIterator](toProp)
|
||||
}
|
||||
|
||||
// AppendTo appends the given IRIs to the To property of 'with'.
|
||||
func AppendTo(with WithTo, to ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsToPropertyIterator] {
|
||||
toProp := with.GetActivityStreamsTo()
|
||||
if toProp == nil {
|
||||
toProp = streams.NewActivityStreamsToProperty()
|
||||
with.SetActivityStreamsTo(toProp)
|
||||
}
|
||||
return toProp
|
||||
}, to...)
|
||||
}
|
||||
|
||||
// GetCc returns the IRIs contained in the Cc property of 'with'. Panics on entries with missing ID.
|
||||
func GetCc(with WithCc) []*url.URL {
|
||||
ccProp := with.GetActivityStreamsCc()
|
||||
return getIRIs[vocab.ActivityStreamsCcPropertyIterator](ccProp)
|
||||
}
|
||||
|
||||
// AppendCc appends the given IRIs to the Cc property of 'with'.
|
||||
func AppendCc(with WithCc, cc ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsCcPropertyIterator] {
|
||||
ccProp := with.GetActivityStreamsCc()
|
||||
if ccProp == nil {
|
||||
ccProp = streams.NewActivityStreamsCcProperty()
|
||||
with.SetActivityStreamsCc(ccProp)
|
||||
}
|
||||
return ccProp
|
||||
}, cc...)
|
||||
}
|
||||
|
||||
// GetBcc returns the IRIs contained in the Bcc property of 'with'. Panics on entries with missing ID.
|
||||
func GetBcc(with WithBcc) []*url.URL {
|
||||
bccProp := with.GetActivityStreamsBcc()
|
||||
return getIRIs[vocab.ActivityStreamsBccPropertyIterator](bccProp)
|
||||
}
|
||||
|
||||
// AppendBcc appends the given IRIs to the Bcc property of 'with'.
|
||||
func AppendBcc(with WithBcc, bcc ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsBccPropertyIterator] {
|
||||
bccProp := with.GetActivityStreamsBcc()
|
||||
if bccProp == nil {
|
||||
bccProp = streams.NewActivityStreamsBccProperty()
|
||||
with.SetActivityStreamsBcc(bccProp)
|
||||
}
|
||||
return bccProp
|
||||
}, bcc...)
|
||||
}
|
||||
|
||||
// GetActor returns the IRIs contained in the Actor property of 'with'. Panics on entries with missing ID.
|
||||
func GetActor(with WithActor) []*url.URL {
|
||||
actorProp := with.GetActivityStreamsActor()
|
||||
return getIRIs[vocab.ActivityStreamsActorPropertyIterator](actorProp)
|
||||
}
|
||||
|
||||
// AppendActor appends the given IRIs to the Actor property of 'with'.
|
||||
func AppendActor(with WithActor, actor ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsActorPropertyIterator] {
|
||||
actorProp := with.GetActivityStreamsActor()
|
||||
if actorProp == nil {
|
||||
actorProp = streams.NewActivityStreamsActorProperty()
|
||||
with.SetActivityStreamsActor(actorProp)
|
||||
}
|
||||
return actorProp
|
||||
}, actor...)
|
||||
}
|
||||
|
||||
// GetAttributedTo returns the IRIs contained in the AttributedTo property of 'with'. Panics on entries with missing ID.
|
||||
func GetAttributedTo(with WithAttributedTo) []*url.URL {
|
||||
attribProp := with.GetActivityStreamsAttributedTo()
|
||||
return getIRIs[vocab.ActivityStreamsAttributedToPropertyIterator](attribProp)
|
||||
}
|
||||
|
||||
// AppendAttributedTo appends the given IRIs to the AttributedTo property of 'with'.
|
||||
func AppendAttributedTo(with WithAttributedTo, attribTo ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsAttributedToPropertyIterator] {
|
||||
attribProp := with.GetActivityStreamsAttributedTo()
|
||||
if attribProp == nil {
|
||||
attribProp = streams.NewActivityStreamsAttributedToProperty()
|
||||
with.SetActivityStreamsAttributedTo(attribProp)
|
||||
}
|
||||
return attribProp
|
||||
}, attribTo...)
|
||||
}
|
||||
|
||||
// GetInReplyTo returns the IRIs contained in the InReplyTo property of 'with'. Panics on entries with missing ID.
|
||||
func GetInReplyTo(with WithInReplyTo) []*url.URL {
|
||||
replyProp := with.GetActivityStreamsInReplyTo()
|
||||
return getIRIs[vocab.ActivityStreamsInReplyToPropertyIterator](replyProp)
|
||||
}
|
||||
|
||||
// AppendInReplyTo appends the given IRIs to the InReplyTo property of 'with'.
|
||||
func AppendInReplyTo(with WithInReplyTo, replyTo ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsInReplyToPropertyIterator] {
|
||||
replyProp := with.GetActivityStreamsInReplyTo()
|
||||
if replyProp == nil {
|
||||
replyProp = streams.NewActivityStreamsInReplyToProperty()
|
||||
with.SetActivityStreamsInReplyTo(replyProp)
|
||||
}
|
||||
return replyProp
|
||||
}, replyTo...)
|
||||
}
|
||||
|
||||
// GetPublished returns the time contained in the Published property of 'with'.
|
||||
func GetPublished(with WithPublished) time.Time {
|
||||
publishProp := with.GetActivityStreamsPublished()
|
||||
if publishProp == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return publishProp.Get()
|
||||
}
|
||||
|
||||
// SetPublished sets the given time on the Published property of 'with'.
|
||||
func SetPublished(with WithPublished, published time.Time) {
|
||||
publishProp := with.GetActivityStreamsPublished()
|
||||
if publishProp == nil {
|
||||
publishProp = streams.NewActivityStreamsPublishedProperty()
|
||||
with.SetActivityStreamsPublished(publishProp)
|
||||
}
|
||||
publishProp.Set(published)
|
||||
}
|
||||
|
||||
// GetEndTime returns the time contained in the EndTime property of 'with'.
|
||||
func GetEndTime(with WithEndTime) time.Time {
|
||||
endTimeProp := with.GetActivityStreamsEndTime()
|
||||
if endTimeProp == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return endTimeProp.Get()
|
||||
}
|
||||
|
||||
// SetEndTime sets the given time on the EndTime property of 'with'.
|
||||
func SetEndTime(with WithEndTime, end time.Time) {
|
||||
endTimeProp := with.GetActivityStreamsEndTime()
|
||||
if endTimeProp == nil {
|
||||
endTimeProp = streams.NewActivityStreamsEndTimeProperty()
|
||||
with.SetActivityStreamsEndTime(endTimeProp)
|
||||
}
|
||||
endTimeProp.Set(end)
|
||||
}
|
||||
|
||||
// GetEndTime returns the times contained in the Closed property of 'with'.
|
||||
func GetClosed(with WithClosed) []time.Time {
|
||||
closedProp := with.GetActivityStreamsClosed()
|
||||
if closedProp == nil || closedProp.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
closed := make([]time.Time, 0, closedProp.Len())
|
||||
for i := 0; i < closedProp.Len(); i++ {
|
||||
at := closedProp.At(i)
|
||||
if t := at.GetXMLSchemaDateTime(); !t.IsZero() {
|
||||
closed = append(closed, t)
|
||||
}
|
||||
}
|
||||
return closed
|
||||
}
|
||||
|
||||
// AppendClosed appends the given times to the Closed property of 'with'.
|
||||
func AppendClosed(with WithClosed, closed ...time.Time) {
|
||||
if len(closed) == 0 {
|
||||
return
|
||||
}
|
||||
closedProp := with.GetActivityStreamsClosed()
|
||||
if closedProp == nil {
|
||||
closedProp = streams.NewActivityStreamsClosedProperty()
|
||||
with.SetActivityStreamsClosed(closedProp)
|
||||
}
|
||||
for _, closed := range closed {
|
||||
closedProp.AppendXMLSchemaDateTime(closed)
|
||||
}
|
||||
}
|
||||
|
||||
// GetVotersCount returns the integer contained in the VotersCount property of 'with', if found.
|
||||
func GetVotersCount(with WithVotersCount) int {
|
||||
votersProp := with.GetTootVotersCount()
|
||||
if votersProp == nil {
|
||||
return 0
|
||||
}
|
||||
return votersProp.Get()
|
||||
}
|
||||
|
||||
// SetVotersCount sets the given count on the VotersCount property of 'with'.
|
||||
func SetVotersCount(with WithVotersCount, count int) {
|
||||
votersProp := with.GetTootVotersCount()
|
||||
if votersProp == nil {
|
||||
votersProp = streams.NewTootVotersCountProperty()
|
||||
with.SetTootVotersCount(votersProp)
|
||||
}
|
||||
votersProp.Set(count)
|
||||
}
|
||||
|
||||
func getIRIs[T TypeOrIRI](prop Property[T]) []*url.URL {
|
||||
if prop == nil || prop.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
ids := make([]*url.URL, 0, prop.Len())
|
||||
for i := 0; i < prop.Len(); i++ {
|
||||
at := prop.At(i)
|
||||
if t := at.GetType(); t != nil {
|
||||
id := GetJSONLDId(t)
|
||||
if id != nil {
|
||||
ids = append(ids, id)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if at.IsIRI() {
|
||||
id := at.GetIRI()
|
||||
if id != nil {
|
||||
ids = append(ids, id)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func appendIRIs[T TypeOrIRI](getProp func() Property[T], iri ...*url.URL) {
|
||||
if len(iri) == 0 {
|
||||
return
|
||||
}
|
||||
prop := getProp()
|
||||
if prop == nil {
|
||||
// check outside loop.
|
||||
panic("prop not set")
|
||||
}
|
||||
for _, iri := range iri {
|
||||
prop.AppendIRI(iri)
|
||||
}
|
||||
}
|
||||
|
||||
// panicfAt panics with a call to gtserror.NewfAt() with given args (+1 to calldepth).
|
||||
// func panicfAt(calldepth int, msg string, args ...any) {
|
||||
// panic(gtserror.NewfAt(calldepth+1, msg, args...))
|
||||
// }
|
||||
Loading…
Add table
Add a link
Reference in a new issue