Begin porting C2S side effect behaviors.
このコミットが含まれているのは:
コミット
0f7dce6839
|
@ -125,10 +125,8 @@ type FederatingWrappedCallbacks struct {
|
||||||
// db is the Database the FederatingWrappedCallbacks should use.
|
// db is the Database the FederatingWrappedCallbacks should use.
|
||||||
db Database
|
db Database
|
||||||
// inboxIRI is the inboxIRI that is handling this callback.
|
// inboxIRI is the inboxIRI that is handling this callback.
|
||||||
// TODO: Populate
|
|
||||||
inboxIRI *url.URL
|
inboxIRI *url.URL
|
||||||
// newTransport creates a new Transport.
|
// newTransport creates a new Transport.
|
||||||
// TODO: Populate
|
|
||||||
newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
|
newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,7 +818,7 @@ func (w FederatingWrappedCallbacks) announce(c context.Context, a vocab.Activity
|
||||||
}
|
}
|
||||||
// Get 'shares' value, defaulting to a collection.
|
// Get 'shares' value, defaulting to a collection.
|
||||||
sharesT := shares.GetType()
|
sharesT := shares.GetType()
|
||||||
if sharesT== nil {
|
if sharesT == nil {
|
||||||
col := streams.NewActivityStreamsCollection()
|
col := streams.NewActivityStreamsCollection()
|
||||||
sharesT = col
|
sharesT = col
|
||||||
shares.SetActivityStreamsCollection(col)
|
shares.SetActivityStreamsCollection(col)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package pub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-fed/activity/streams/vocab"
|
"github.com/go-fed/activity/streams/vocab"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
// inReplyToer is an ActivityStreams type with a 'inReplyTo' property
|
// inReplyToer is an ActivityStreams type with a 'inReplyTo' property
|
||||||
|
@ -49,26 +50,31 @@ type publisheder interface {
|
||||||
// toer is an ActivityStreams type with a 'to' property
|
// toer is an ActivityStreams type with a 'to' property
|
||||||
type toer interface {
|
type toer interface {
|
||||||
GetActivityStreamsTo() vocab.ActivityStreamsToProperty
|
GetActivityStreamsTo() vocab.ActivityStreamsToProperty
|
||||||
|
SetActivityStreamsTo(i vocab.ActivityStreamsToProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// btoer is an ActivityStreams type with a 'bto' property
|
// btoer is an ActivityStreams type with a 'bto' property
|
||||||
type btoer interface {
|
type btoer interface {
|
||||||
GetActivityStreamsBto() vocab.ActivityStreamsBtoProperty
|
GetActivityStreamsBto() vocab.ActivityStreamsBtoProperty
|
||||||
|
SetActivityStreamsBto(i vocab.ActivityStreamsBtoProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ccer is an ActivityStreams type with a 'cc' property
|
// ccer is an ActivityStreams type with a 'cc' property
|
||||||
type ccer interface {
|
type ccer interface {
|
||||||
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
|
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
|
||||||
|
SetActivityStreamsCc(i vocab.ActivityStreamsCcProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bccer is an ActivityStreams type with a 'bcc' property
|
// bccer is an ActivityStreams type with a 'bcc' property
|
||||||
type bccer interface {
|
type bccer interface {
|
||||||
GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
|
GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
|
||||||
|
SetActivityStreamsBcc(i vocab.ActivityStreamsBccProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// audiencer is an ActivityStreams type with a 'audience' property
|
// audiencer is an ActivityStreams type with a 'audience' property
|
||||||
type audiencer interface {
|
type audiencer interface {
|
||||||
GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
|
GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
|
||||||
|
SetActivityStreamsAudience(i vocab.ActivityStreamsAudienceProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inboxer is an ActivityStreams type with a 'inbox' property
|
// inboxer is an ActivityStreams type with a 'inbox' property
|
||||||
|
@ -79,6 +85,7 @@ type inboxer interface {
|
||||||
// attributedToer is an ActivityStreams type with a 'attributedTo' property
|
// attributedToer is an ActivityStreams type with a 'attributedTo' property
|
||||||
type attributedToer interface {
|
type attributedToer interface {
|
||||||
GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
|
GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
|
||||||
|
SetActivityStreamsAttributedTo(i vocab.ActivityStreamsAttributedToProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// likeser is an ActivityStreams type with a 'likes' property
|
// likeser is an ActivityStreams type with a 'likes' property
|
||||||
|
@ -98,3 +105,8 @@ type actorer interface {
|
||||||
GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
|
GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
|
||||||
SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
|
SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// appendIRIer is an ActivityStreams type that can Append IRIs.
|
||||||
|
type appendIRIer interface {
|
||||||
|
AppendIRI(v *url.URL)
|
||||||
|
}
|
||||||
|
|
|
@ -99,8 +99,8 @@ func (a *sideEffectActor) PostInbox(c context.Context, inboxIRI *url.URL, activi
|
||||||
wrapped, other := a.s2s.Callbacks(c)
|
wrapped, other := a.s2s.Callbacks(c)
|
||||||
// Populate side channels.
|
// Populate side channels.
|
||||||
wrapped.db = a.db
|
wrapped.db = a.db
|
||||||
wrapped.inboxIRI= inboxIRI
|
wrapped.inboxIRI = inboxIRI
|
||||||
wrapped.newTransport= a.s2s.NewTransport
|
wrapped.newTransport = a.s2s.NewTransport
|
||||||
if err = wrapped.disjoint(other); err != nil {
|
if err = wrapped.disjoint(other); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ package pub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-fed/activity/streams"
|
||||||
"github.com/go-fed/activity/streams/vocab"
|
"github.com/go-fed/activity/streams/vocab"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SocialWrappedCallbacks lists the callback functions that already have some
|
// SocialWrappedCallbacks lists the callback functions that already have some
|
||||||
|
@ -15,8 +18,7 @@ type SocialWrappedCallbacks struct {
|
||||||
//
|
//
|
||||||
// The wrapping callback for the Social Protocol copies the actor(s) to
|
// The wrapping callback for the Social Protocol copies the actor(s) to
|
||||||
// the 'attributedTo' property, copying recipients between the Create
|
// the 'attributedTo' property, copying recipients between the Create
|
||||||
// activity and all objects, save the entry in the database, and adds it
|
// activity and all objects. It then saves the entry in the database.
|
||||||
// to the outbox.
|
|
||||||
Create func(context.Context, vocab.ActivityStreamsCreate) error
|
Create func(context.Context, vocab.ActivityStreamsCreate) error
|
||||||
// Update handles additional side effects for the Update ActivityStreams
|
// Update handles additional side effects for the Update ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
|
@ -58,9 +60,16 @@ type SocialWrappedCallbacks struct {
|
||||||
//
|
//
|
||||||
// TODO: Describe
|
// TODO: Describe
|
||||||
Block func(context.Context, vocab.ActivityStreamsBlock) error
|
Block func(context.Context, vocab.ActivityStreamsBlock) error
|
||||||
|
|
||||||
|
// Sidechannel data -- this is set at request handling time. These must
|
||||||
|
// be set before the callbacks are used.
|
||||||
|
|
||||||
// db is the Database the SocialWrappedCallbacks should use. It must be
|
// db is the Database the SocialWrappedCallbacks should use. It must be
|
||||||
// set before calling the callbacks.
|
// set before calling the callbacks.
|
||||||
db Database
|
db Database
|
||||||
|
// deliverable is a sidechannel out, indicating if the handled activity
|
||||||
|
// should be delivered to a peer.
|
||||||
|
deliverable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// disjoint ensures that the functions given do not share a type signature with
|
// disjoint ensures that the functions given do not share a type signature with
|
||||||
|
@ -104,8 +113,6 @@ func (w SocialWrappedCallbacks) callbacks() []interface{} {
|
||||||
w.update,
|
w.update,
|
||||||
w.deleteFn,
|
w.deleteFn,
|
||||||
w.follow,
|
w.follow,
|
||||||
w.accept,
|
|
||||||
w.reject,
|
|
||||||
w.add,
|
w.add,
|
||||||
w.remove,
|
w.remove,
|
||||||
w.like,
|
w.like,
|
||||||
|
@ -116,120 +123,85 @@ func (w SocialWrappedCallbacks) callbacks() []interface{} {
|
||||||
|
|
||||||
// create implements the social Create activity side effects.
|
// create implements the social Create activity side effects.
|
||||||
func (w SocialWrappedCallbacks) create(c context.Context, a vocab.ActivityStreamsCreate) error {
|
func (w SocialWrappedCallbacks) create(c context.Context, a vocab.ActivityStreamsCreate) error {
|
||||||
*deliverable = true
|
w.deliverable = true
|
||||||
if s.LenObject() == 0 {
|
op := a.GetActivityStreamsObject()
|
||||||
return errObjectRequired
|
if op == nil || op.Len() == 0 {
|
||||||
|
return ErrObjectRequired
|
||||||
}
|
}
|
||||||
c = s.Raw()
|
// Obtain all actor IRIs.
|
||||||
// When a Create activity is posted, the actor of the activity
|
actors := a.GetActivityStreamsActor()
|
||||||
// SHOULD be copied onto the object's attributedTo field.
|
createActorIds := make(map[string]*url.URL, actors.Len())
|
||||||
// Presumably only if it doesn't already exist, to prevent
|
for iter := actors.Begin(); iter != actors.End(); iter = iter.Next() {
|
||||||
// duplicate deliveries.
|
id, err := ToId(iter)
|
||||||
createActorIds := make(map[string]interface{})
|
if err != nil {
|
||||||
for i := 0; i < c.ActorLen(); i++ {
|
return err
|
||||||
if c.IsActorObject(i) {
|
|
||||||
obj := c.GetActorObject(i)
|
|
||||||
id := obj.GetId()
|
|
||||||
createActorIds[id.String()] = obj
|
|
||||||
} else if c.IsActorLink(i) {
|
|
||||||
l := c.GetActorLink(i)
|
|
||||||
href := l.GetHref()
|
|
||||||
createActorIds[href.String()] = l
|
|
||||||
} else if c.IsActorIRI(i) {
|
|
||||||
iri := c.GetActorIRI(i)
|
|
||||||
createActorIds[iri.String()] = iri
|
|
||||||
}
|
}
|
||||||
|
createActorIds[id.String()] = id
|
||||||
}
|
}
|
||||||
var obj []vocab.ObjectType
|
// Obtain each object's 'attributedTo' IRIs.
|
||||||
for i := 0; i < c.ObjectLen(); i++ {
|
objectAttributedToIds := make([]map[string]*url.URL, op.Len())
|
||||||
if !c.IsObject(i) {
|
|
||||||
return fmt.Errorf("unsupported: Create Activity with 'object' that is only an IRI")
|
|
||||||
}
|
|
||||||
obj = append(obj, c.GetObject(i))
|
|
||||||
}
|
|
||||||
objectAttributedToIds := make([]map[string]interface{}, len(obj))
|
|
||||||
for i := range objectAttributedToIds {
|
for i := range objectAttributedToIds {
|
||||||
objectAttributedToIds[i] = make(map[string]interface{})
|
objectAttributedToIds[i] = make(map[string]*url.URL)
|
||||||
}
|
}
|
||||||
for k, o := range obj {
|
for i := 0; i < op.Len(); i++ {
|
||||||
for i := 0; i < o.AttributedToLen(); i++ {
|
t := op.At(i).GetType()
|
||||||
if o.IsAttributedToObject(i) {
|
attrToer, ok := t.(attributedToer)
|
||||||
at := o.GetAttributedToObject(i)
|
if !ok {
|
||||||
id := o.GetId()
|
continue
|
||||||
objectAttributedToIds[k][id.String()] = at
|
}
|
||||||
} else if o.IsAttributedToLink(i) {
|
attr := attrToer.GetActivityStreamsAttributedTo()
|
||||||
at := o.GetAttributedToLink(i)
|
if attr == nil {
|
||||||
href := at.GetHref()
|
attr = streams.NewActivityStreamsAttributedToProperty()
|
||||||
objectAttributedToIds[k][href.String()] = at
|
attrToer.SetActivityStreamsAttributedTo(attr)
|
||||||
} else if o.IsAttributedToIRI(i) {
|
}
|
||||||
iri := o.GetAttributedToIRI(i)
|
for iter := attr.Begin(); iter != attr.End(); iter = iter.Next() {
|
||||||
objectAttributedToIds[k][iri.String()] = iri
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
objectAttributedToIds[i][id.String()] = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Put all missing actor IRIs onto all object attributedTo properties.
|
||||||
for k, v := range createActorIds {
|
for k, v := range createActorIds {
|
||||||
for i, attributedToMap := range objectAttributedToIds {
|
for i, attributedToMap := range objectAttributedToIds {
|
||||||
if _, ok := attributedToMap[k]; !ok {
|
if _, ok := attributedToMap[k]; !ok {
|
||||||
var iri *url.URL
|
t := op.At(i).GetType()
|
||||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
attrToer, ok := t.(attributedToer)
|
||||||
if !vObj.HasId() {
|
if !ok {
|
||||||
return fmt.Errorf("create actor object missing id")
|
continue
|
||||||
}
|
|
||||||
iri = vObj.GetId()
|
|
||||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
|
||||||
if !vLink.HasHref() {
|
|
||||||
return fmt.Errorf("create actor link missing href")
|
|
||||||
}
|
|
||||||
iri = vLink.GetHref()
|
|
||||||
} else if vIRI, ok := v.(*url.URL); ok {
|
|
||||||
iri = vIRI
|
|
||||||
}
|
}
|
||||||
obj[i].AppendAttributedToIRI(iri)
|
attr := attrToer.GetActivityStreamsAttributedTo()
|
||||||
|
attr.AppendIRI(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Put all missing object attributedTo IRIs onto the actor property.
|
||||||
for _, attributedToMap := range objectAttributedToIds {
|
for _, attributedToMap := range objectAttributedToIds {
|
||||||
for k, v := range attributedToMap {
|
for k, v := range attributedToMap {
|
||||||
if _, ok := createActorIds[k]; !ok {
|
if _, ok := createActorIds[k]; !ok {
|
||||||
var iri *url.URL
|
actors.AppendIRI(v)
|
||||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
|
||||||
if !vObj.HasId() {
|
|
||||||
return fmt.Errorf("attributedTo object missing id")
|
|
||||||
}
|
|
||||||
iri = vObj.GetId()
|
|
||||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
|
||||||
if !vLink.HasHref() {
|
|
||||||
return fmt.Errorf("attributedTo link missing href")
|
|
||||||
}
|
|
||||||
iri = vLink.GetHref()
|
|
||||||
} else if vIRI, ok := v.(*url.URL); ok {
|
|
||||||
iri = vIRI
|
|
||||||
}
|
|
||||||
c.AppendActorIRI(iri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// As such, a server SHOULD copy any recipients of the Create activity to its
|
// Copy over the 'to', 'bto', 'cc', 'bcc', and 'audience' recipients
|
||||||
// object upon initial distribution, and likewise with copying recipients from
|
// between the activity and all child objects and vice versa.
|
||||||
// the object to the wrapping Create activity.
|
if err := normalizeRecipients(a); err != nil {
|
||||||
if err := f.sameRecipients(c); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Create requires the client application to persist the 'object' that
|
// Persist all objects we've created, which will include sensitive
|
||||||
// was created.
|
// recipients such as 'bcc' and 'bto'.
|
||||||
for _, o := range obj {
|
for i := 0; i < op.Len(); i++ {
|
||||||
if err := f.App.Set(ctx, o); err != nil {
|
obj := op.At(i).GetType()
|
||||||
|
// TODO: Lock
|
||||||
|
if err := w.db.Create(c, obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Persist the above changes in the outbox
|
if w.Create != nil {
|
||||||
var err error
|
return w.Create(c, a)
|
||||||
*toAddToOutbox = make(map[string]interface{})
|
|
||||||
*toAddToOutbox, err = c.Serialize()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return f.ClientCallbacker.Create(ctx, s)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// update implements the social Update activity side effects.
|
// update implements the social Update activity side effects.
|
||||||
|
|
261
pub/util.go
261
pub/util.go
|
@ -539,3 +539,264 @@ func mustHaveActivityActorsMatchObjectActors(a vocab.ActivityType) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalizeRecipients ensures the activity and object have the same 'to',
|
||||||
|
// 'bto', 'cc', 'bcc', and 'audience' properties. Copy the Activity's recipients
|
||||||
|
// to objects, and the objects to the activity, but does NOT copy objects'
|
||||||
|
// recipients to each other.
|
||||||
|
func normalizeRecipients(a vocab.ActivityStreamsCreate) error {
|
||||||
|
// Phase 0: Acquire all recipients on the activity.
|
||||||
|
//
|
||||||
|
// Obtain the actorTo map
|
||||||
|
actorToMap := make(map[string]interface{})
|
||||||
|
actorTo := a.GetActivityStreamsTo()
|
||||||
|
if actorTo == nil {
|
||||||
|
actorTo = streams.NewActivityStreamsToProperty()
|
||||||
|
a.SetActivityStreamsTo(actorTo)
|
||||||
|
}
|
||||||
|
for iter := actorTo.Begin(); iter != actorTo.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorToMap[id.String()] = id
|
||||||
|
}
|
||||||
|
// Obtain the actorBto map
|
||||||
|
actorBtoMap := make(map[string]interface{})
|
||||||
|
actorBto := a.GetActivityStreamsBto()
|
||||||
|
if actorBto == nil {
|
||||||
|
actorBto = streams.NewActivityStreamsBtoProperty()
|
||||||
|
a.SetActivityStreamsBto(actorBto)
|
||||||
|
}
|
||||||
|
for iter := actorBto.Begin(); iter != actorBto.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorBtoMap[id.String()] = id
|
||||||
|
}
|
||||||
|
// Obtain the actorCc map
|
||||||
|
actorCcMap := make(map[string]interface{})
|
||||||
|
actorCc := a.GetActivityStreamsCc()
|
||||||
|
if actorCc == nil {
|
||||||
|
actorCc = streams.NewActivityStreamsCcProperty()
|
||||||
|
a.SetActivityStreamsCc(actorCc)
|
||||||
|
}
|
||||||
|
for iter := actorCc.Begin(); iter != actorCc.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorCcMap[id.String()] = id
|
||||||
|
}
|
||||||
|
// Obtain the actorBcc map
|
||||||
|
actorBccMap := make(map[string]interface{})
|
||||||
|
actorBcc := a.GetActivityStreamsBcc()
|
||||||
|
if actorBcc == nil {
|
||||||
|
actorBcc = streams.NewActivityStreamsBccProperty()
|
||||||
|
a.SetActivityStreamsBcc(actorBcc)
|
||||||
|
}
|
||||||
|
for iter := actorBcc.Begin(); iter != actorBcc.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorBccMap[id.String()] = id
|
||||||
|
}
|
||||||
|
// Obtain the actorAudience map
|
||||||
|
actorAudienceMap := make(map[string]interface{})
|
||||||
|
actorAudience := a.GetActivityStreamsAudience()
|
||||||
|
if actorAudience == nil {
|
||||||
|
actorAudience = streams.NewActivityStreamsAudienceProperty()
|
||||||
|
a.SetActivityStreamsAudience(actorAudience)
|
||||||
|
}
|
||||||
|
for iter := actorAudience.Begin(); iter != actorAudience.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorAudienceMap[id.String()] = id
|
||||||
|
}
|
||||||
|
// Obtain the objects maps for each recipient type.
|
||||||
|
o := a.GetActivityStreamsObject()
|
||||||
|
objsTo := make([]map[string]interface{}, o.Len())
|
||||||
|
objsBto := make([]map[string]interface{}, o.Len())
|
||||||
|
objsCco := make([]map[string]interface{}, o.Len())
|
||||||
|
objsBcc := make([]map[string]interface{}, o.Len())
|
||||||
|
objsAudience := make([]map[string]interface{}, o.Len())
|
||||||
|
for i := 0; i < o.Len(); i++ {
|
||||||
|
// Phase 1: Acquire all existing recipients on the object.
|
||||||
|
//
|
||||||
|
// Object to
|
||||||
|
objsTo[i] = make(map[string]interface{})
|
||||||
|
var oTo vocab.ActivityStreamsToProperty
|
||||||
|
if tr, ok := o.At(i).(toer); !ok {
|
||||||
|
return fmt.Errorf("the Create object at %d has no 'to' property", i)
|
||||||
|
} else {
|
||||||
|
oTo = tr.GetActivityStreamsTo()
|
||||||
|
if oTo == nil {
|
||||||
|
oTo = streams.NewActivityStreamsToProperty()
|
||||||
|
tr.SetActivityStreamsTo(oTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iter := oTo.Begin(); iter != oTo.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objsTo[i][id.String()] = id
|
||||||
|
}
|
||||||
|
// Object bto
|
||||||
|
objsBto[i] = make(map[string]interface{})
|
||||||
|
var oBto vocab.ActivityStreamsBtoProperty
|
||||||
|
if tr, ok := o.At(i).(btoer); !ok {
|
||||||
|
return fmt.Errorf("the Create object at %d has no 'bto' property", i)
|
||||||
|
} else {
|
||||||
|
oBto = tr.GetActivityStreamsBto()
|
||||||
|
if oBto == nil {
|
||||||
|
oBto = streams.NewActivityStreamsBtoProperty()
|
||||||
|
tr.SetActivityStreamsBto(oBto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iter := oBto.Begin(); iter != oBto.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objsBto[i][id.String()] = id
|
||||||
|
}
|
||||||
|
// Object cc
|
||||||
|
objsCc[i] = make(map[string]interface{})
|
||||||
|
var oCc vocab.ActivityStreamsCcProperty
|
||||||
|
if tr, ok := o.At(i).(ccer); !ok {
|
||||||
|
return fmt.Errorf("the Create object at %d has no 'cc' property", i)
|
||||||
|
} else {
|
||||||
|
oCc = tr.GetActivityStreamsCc()
|
||||||
|
if oCc == nil {
|
||||||
|
oCc = streams.NewActivityStreamsCcProperty()
|
||||||
|
tr.SetActivityStreamsCc(oCc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iter := oCc.Begin(); iter != oCc.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objsCc[i][id.String()] = id
|
||||||
|
}
|
||||||
|
// Object bcc
|
||||||
|
objsBcc[i] = make(map[string]interface{})
|
||||||
|
var oBcc vocab.ActivityStreamsBccProperty
|
||||||
|
if tr, ok := o.At(i).(bccer); !ok {
|
||||||
|
return fmt.Errorf("the Create object at %d has no 'bcc' property", i)
|
||||||
|
} else {
|
||||||
|
oBcc = tr.GetActivityStreamsBcc()
|
||||||
|
if oBcc == nil {
|
||||||
|
oBcc = streams.NewActivityStreamsBccProperty()
|
||||||
|
tr.SetActivityStreamsBcc(oBcc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iter := oBcc.Begin(); iter != oBcc.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objsBcc[i][id.String()] = id
|
||||||
|
}
|
||||||
|
// Object audience
|
||||||
|
objsAudience[i] = make(map[string]interface{})
|
||||||
|
var oAudience vocab.ActivityStreamsAudienceProperty
|
||||||
|
if tr, ok := o.At(i).(audiencer); !ok {
|
||||||
|
return fmt.Errorf("the Create object at %d has no 'audience' property", i)
|
||||||
|
} else {
|
||||||
|
oAudience = tr.GetActivityStreamsAudience()
|
||||||
|
if oAudience == nil {
|
||||||
|
oAudience = streams.NewActivityStreamsAudienceProperty()
|
||||||
|
tr.SetActivityStreamsAudience(oAudience)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iter := oAudience.Begin(); iter != oAudience.End(); iter = iter.Next() {
|
||||||
|
id, err := ToId(iter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objsAudience[i][id.String()] = id
|
||||||
|
}
|
||||||
|
// Phase 2: Apply missing recipients to the object from the
|
||||||
|
// activity.
|
||||||
|
//
|
||||||
|
// Activity to -> Object to
|
||||||
|
for k, v := range actorToMap {
|
||||||
|
if _, ok := objsTo[i][k]; !ok {
|
||||||
|
oTo.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Activity bto -> Object bto
|
||||||
|
for k, v := range actorBtoMap {
|
||||||
|
if _, ok := objsBto[i][k]; !ok {
|
||||||
|
oBto.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Activity cc -> Object cc
|
||||||
|
for k, v := range actorCcMap {
|
||||||
|
if _, ok := objsCc[i][k]; !ok {
|
||||||
|
oCc.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Activity bcc -> Object bcc
|
||||||
|
for k, v := range actorBccMap {
|
||||||
|
if _, ok := objsBcc[i][k]; !ok {
|
||||||
|
oBcc.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Activity audience -> Object audience
|
||||||
|
for k, v := range actorAudienceMap {
|
||||||
|
if _, ok := objsAudience[i][k]; !ok {
|
||||||
|
oAudience.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Phase 3: Apply missing recipients to the activity from the objects.
|
||||||
|
//
|
||||||
|
// Object to -> Activity to
|
||||||
|
for i := 0; i < len(objsTo); i++ {
|
||||||
|
for k, v := range objsTo[i] {
|
||||||
|
if _, ok := actorToMap[k]; !ok {
|
||||||
|
actorTo.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Object bto -> Activity bto
|
||||||
|
for i := 0; i < len(objsBto); i++ {
|
||||||
|
for k, v := range objsBto[i] {
|
||||||
|
if _, ok := actorBtoMap[k]; !ok {
|
||||||
|
actorBto.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Object cc -> Activity cc
|
||||||
|
for i := 0; i < len(objsCc); i++ {
|
||||||
|
for k, v := range objsCc[i] {
|
||||||
|
if _, ok := actorCcMap[k]; !ok {
|
||||||
|
actorCc.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Object bcc -> Activity bcc
|
||||||
|
for i := 0; i < len(objsBcc); i++ {
|
||||||
|
for k, v := range objsBcc[i] {
|
||||||
|
if _, ok := actorBccMap[k]; !ok {
|
||||||
|
actorBcc.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Object audience -> Activity audience
|
||||||
|
for i := 0; i < len(objsAudience); i++ {
|
||||||
|
for k, v := range objsAudience[i] {
|
||||||
|
if _, ok := actorAudienceMap[k]; !ok {
|
||||||
|
actorAudience.AppendIRI(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
読み込み中…
新しいイシューから参照