diff options
Diffstat (limited to 'internal/ap')
| -rw-r--r-- | internal/ap/collections.go | 12 | ||||
| -rw-r--r-- | internal/ap/extract.go | 47 | ||||
| -rw-r--r-- | internal/ap/interfaces.go | 16 | ||||
| -rw-r--r-- | internal/ap/normalize.go | 76 | ||||
| -rw-r--r-- | internal/ap/util.go | 43 | 
5 files changed, 121 insertions, 73 deletions
| diff --git a/internal/ap/collections.go b/internal/ap/collections.go index 471dae0a1..e86d989ff 100644 --- a/internal/ap/collections.go +++ b/internal/ap/collections.go @@ -32,10 +32,10 @@ import (  func ToCollectionPageIterator(t vocab.Type) (CollectionPageIterator, error) {  	switch name := t.GetTypeName(); name {  	case ObjectCollectionPage: -		t := t.(vocab.ActivityStreamsCollectionPage) //nolint:forcetypeassert +		t := t.(vocab.ActivityStreamsCollectionPage)  		return WrapCollectionPage(t), nil  	case ObjectOrderedCollectionPage: -		t := t.(vocab.ActivityStreamsOrderedCollectionPage) //nolint:forcetypeassert +		t := t.(vocab.ActivityStreamsOrderedCollectionPage)  		return WrapOrderedCollectionPage(t), nil  	default:  		return nil, fmt.Errorf("%T(%s) was not CollectionPage-like", t, name) @@ -74,7 +74,7 @@ func (iter *regularCollectionPageIterator) PrevPage() WithIRI {  	return iter.GetActivityStreamsPrev()  } -func (iter *regularCollectionPageIterator) NextItem() IteratorItemable { +func (iter *regularCollectionPageIterator) NextItem() TypeOrIRI {  	if !iter.initItems() {  		return nil  	} @@ -83,7 +83,7 @@ func (iter *regularCollectionPageIterator) NextItem() IteratorItemable {  	return cur  } -func (iter *regularCollectionPageIterator) PrevItem() IteratorItemable { +func (iter *regularCollectionPageIterator) PrevItem() TypeOrIRI {  	if !iter.initItems() {  		return nil  	} @@ -130,7 +130,7 @@ func (iter *orderedCollectionPageIterator) PrevPage() WithIRI {  	return iter.GetActivityStreamsPrev()  } -func (iter *orderedCollectionPageIterator) NextItem() IteratorItemable { +func (iter *orderedCollectionPageIterator) NextItem() TypeOrIRI {  	if !iter.initItems() {  		return nil  	} @@ -139,7 +139,7 @@ func (iter *orderedCollectionPageIterator) NextItem() IteratorItemable {  	return cur  } -func (iter *orderedCollectionPageIterator) PrevItem() IteratorItemable { +func (iter *orderedCollectionPageIterator) PrevItem() TypeOrIRI {  	if !iter.initItems() {  		return nil  	} diff --git a/internal/ap/extract.go b/internal/ap/extract.go index 4cefd22dc..41cc5dcbc 100644 --- a/internal/ap/extract.go +++ b/internal/ap/extract.go @@ -35,39 +35,56 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) -// ExtractObject will extract an object vocab.Type from given implementing interface. -func ExtractObject(with WithObject) vocab.Type { +// ExtractObjects will extract object vocab.Types from given implementing interface. +func ExtractObjects(with WithObject) []TypeOrIRI {  	// Extract the attached object (if any). -	obj := with.GetActivityStreamsObject() -	if obj == nil { +	objProp := with.GetActivityStreamsObject() +	if objProp == nil {  		return nil  	} -	// Only support single -	// objects (for now...) -	if obj.Len() != 1 { +	// Check for zero len. +	if objProp.Len() == 0 {  		return nil  	} -	// Extract object vocab.Type. -	return obj.At(0).GetType() +	// Accumulate all of the objects into a slice. +	objs := make([]TypeOrIRI, objProp.Len()) +	for i := 0; i < objProp.Len(); i++ { +		objs[i] = objProp.At(i) +	} + +	return objs  }  // ExtractActivityData will extract the usable data type (e.g. Note, Question, etc) and corresponding JSON, from activity. -func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) (vocab.Type, map[string]any, bool) { +func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeOrIRI, []any, bool) {  	switch typeName := activity.GetTypeName(); {  	// Activity (has "object").  	case isActivity(typeName): -		objType := ExtractObject(activity) -		if objType == nil { +		objTypes := ExtractObjects(activity) +		if len(objTypes) == 0 {  			return nil, nil, false  		} -		objJSON, _ := rawJSON["object"].(map[string]any) -		return objType, objJSON, true + +		var objJSON []any +		switch json := rawJSON["object"].(type) { +		case nil: +			// do nothing +		case map[string]any: +			// Wrap map in slice. +			objJSON = []any{json} +		case []any: +			// Use existing slice. +			objJSON = json +		} + +		return objTypes, objJSON, true  	// IntransitiveAcitivity (no "object").  	case isIntransitiveActivity(typeName): -		return activity, rawJSON, false +		asTypeOrIRI := _TypeOrIRI{activity} // wrap activity. +		return []TypeOrIRI{&asTypeOrIRI}, []any{rawJSON}, true  	// Unknown.  	default: diff --git a/internal/ap/interfaces.go b/internal/ap/interfaces.go index 4538c476f..9e606db62 100644 --- a/internal/ap/interfaces.go +++ b/internal/ap/interfaces.go @@ -247,14 +247,8 @@ type CollectionPageIterator interface {  	NextPage() WithIRI  	PrevPage() WithIRI -	NextItem() IteratorItemable -	PrevItem() IteratorItemable -} - -// IteratorItemable represents the minimum interface for an item in an iterator. -type IteratorItemable interface { -	WithIRI -	WithType +	NextItem() TypeOrIRI +	PrevItem() TypeOrIRI  }  // Flaggable represents the minimum interface for an activitystreams 'Flag' activity. @@ -267,6 +261,12 @@ type Flaggable interface {  	WithObject  } +// TypeOrIRI represents the minimum interface for something that may be a vocab.Type OR IRI. +type TypeOrIRI interface { +	WithIRI +	WithType +} +  // WithJSONLDId represents an activity with JSONLDIdProperty.  type WithJSONLDId interface {  	GetJSONLDId() vocab.JSONLDIdProperty diff --git a/internal/ap/normalize.go b/internal/ap/normalize.go index 52ada2848..192a2d740 100644 --- a/internal/ap/normalize.go +++ b/internal/ap/normalize.go @@ -39,60 +39,48 @@ import (  // This function is a noop if the type passed in is anything except a Create or Update with a Statusable or Accountable as its Object.  func NormalizeIncomingActivity(activity pub.Activity, rawJSON map[string]interface{}) {  	// From the activity extract the data vocab.Type + its "raw" JSON. -	dataType, rawData, ok := ExtractActivityData(activity, rawJSON) -	if !ok { +	dataIfaces, rawData, ok := ExtractActivityData(activity, rawJSON) +	if !ok || len(dataIfaces) != len(rawData) { +		// non-equal lengths *shouldn't* happen, +		// but this is just an integrity check.  		return  	} -	switch dataType.GetTypeName() { -	// "Pollable" types. -	case ActivityQuestion: -		pollable, ok := dataType.(Pollable) -		if !ok { -			return +	// Iterate over the available data. +	for i, dataIface := range dataIfaces { +		// Try to get as vocab.Type, else +		// skip this entry for normalization. +		dataType := dataIface.GetType() +		if dataType == nil { +			continue  		} -		// Normalize the Pollable specific properties. -		NormalizeIncomingPollOptions(pollable, rawData) - -		// Fallthrough to handle -		// the rest as Statusable. -		fallthrough - -	// "Statusable" types. -	case ObjectArticle, -		ObjectDocument, -		ObjectImage, -		ObjectVideo, -		ObjectNote, -		ObjectPage, -		ObjectEvent, -		ObjectPlace, -		ObjectProfile: -		statusable, ok := dataType.(Statusable) +		// Get the raw data map at index, else skip +		// this entry due to impossible normalization. +		rawData, ok := rawData[i].(map[string]any)  		if !ok { -			return +			continue  		} -		// Normalize everything we can on the statusable. -		NormalizeIncomingContent(statusable, rawData) -		NormalizeIncomingAttachments(statusable, rawData) -		NormalizeIncomingSummary(statusable, rawData) -		NormalizeIncomingName(statusable, rawData) - -	// "Accountable" types. -	case ActorApplication, -		ActorGroup, -		ActorOrganization, -		ActorPerson, -		ActorService: -		accountable, ok := dataType.(Accountable) -		if !ok { -			return +		if statusable, ok := ToStatusable(dataType); ok { +			if pollable, ok := ToPollable(dataType); ok { +				// Normalize the Pollable specific properties. +				NormalizeIncomingPollOptions(pollable, rawData) +			} + +			// Normalize everything we can on the statusable. +			NormalizeIncomingContent(statusable, rawData) +			NormalizeIncomingAttachments(statusable, rawData) +			NormalizeIncomingSummary(statusable, rawData) +			NormalizeIncomingName(statusable, rawData) +			continue  		} -		// Normalize everything we can on the accountable. -		NormalizeIncomingSummary(accountable, rawData) +		if accountable, ok := ToAccountable(dataType); ok { +			// Normalize everything we can on the accountable. +			NormalizeIncomingSummary(accountable, rawData) +			continue +		}  	}  } diff --git a/internal/ap/util.go b/internal/ap/util.go new file mode 100644 index 000000000..c810b7985 --- /dev/null +++ b/internal/ap/util.go @@ -0,0 +1,43 @@ +// 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 ( +	"net/url" + +	"github.com/superseriousbusiness/activity/streams/vocab" +) + +// _TypeOrIRI wraps a vocab.Type to implement TypeOrIRI. +type _TypeOrIRI struct { +	vocab.Type +} + +func (t *_TypeOrIRI) GetType() vocab.Type { +	return t.Type +} + +func (t *_TypeOrIRI) GetIRI() *url.URL { +	return nil +} + +func (t *_TypeOrIRI) IsIRI() bool { +	return false +} + +func (t *_TypeOrIRI) SetIRI(*url.URL) {} | 
