Add PostOutbox Create unit tests.
Fix normalizing the recipents between the object and the activity. Also allow the handlers to adjust what gets placed in the outbox, since the client-to-server API allows the server to modify the object before being delivered.
このコミットが含まれているのは:
コミット
2adcc56581
34
pub/fed.go
34
pub/fed.go
|
@ -271,11 +271,11 @@ func (f *federator) PostOutbox(c context.Context, w http.ResponseWriter, r *http
|
|||
if m, err = typer.Serialize(); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if err := f.addToOutbox(c, r, m); err != nil {
|
||||
deliverable := false
|
||||
if err = f.getPostOutboxResolver(c, &deliverable, &m).Deserialize(m); err != nil {
|
||||
return true, err
|
||||
}
|
||||
deliverable := false
|
||||
if err = f.getPostOutboxResolver(c, &deliverable).Deserialize(m); err != nil {
|
||||
if err := f.addToOutbox(c, r, m); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if f.EnableServer && deliverable {
|
||||
|
@ -334,9 +334,9 @@ func (f *federator) addToOutbox(c context.Context, r *http.Request, m map[string
|
|||
return f.App.Set(c, outbox)
|
||||
}
|
||||
|
||||
func (f *federator) getPostOutboxResolver(c context.Context, deliverable *bool) *streams.Resolver {
|
||||
func (f *federator) getPostOutboxResolver(c context.Context, deliverable *bool, toAddToOutbox *map[string]interface{}) *streams.Resolver {
|
||||
return &streams.Resolver{
|
||||
CreateCallback: f.handleClientCreate(c, deliverable),
|
||||
CreateCallback: f.handleClientCreate(c, deliverable, toAddToOutbox),
|
||||
UpdateCallback: f.handleClientUpdate(c, deliverable),
|
||||
DeleteCallback: f.handleClientDelete(c, deliverable),
|
||||
FollowCallback: f.handleClientFollow(c, deliverable),
|
||||
|
@ -351,7 +351,7 @@ func (f *federator) getPostOutboxResolver(c context.Context, deliverable *bool)
|
|||
}
|
||||
}
|
||||
|
||||
func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool) func(s *streams.Create) error {
|
||||
func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool, toAddToOutbox *map[string]interface{}) func(s *streams.Create) error {
|
||||
return func(s *streams.Create) error {
|
||||
*deliverable = true
|
||||
if s.LenObject() == 0 {
|
||||
|
@ -379,12 +379,11 @@ func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool) f
|
|||
}
|
||||
var obj []vocab.ObjectType
|
||||
for i := 0; i < c.ObjectLen(); i++ {
|
||||
if c.IsObject(i) {
|
||||
obj = append(obj, c.GetObject(i))
|
||||
} else if c.IsObjectIRI(i) {
|
||||
if !c.IsObject(i) {
|
||||
// TODO: Fetch IRIs as well
|
||||
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 {
|
||||
|
@ -419,10 +418,6 @@ func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool) f
|
|||
}
|
||||
}
|
||||
}
|
||||
// As such, a server SHOULD copy any recipients of the Create activity to its
|
||||
// object upon initial distribution, and likewise with copying recipients from
|
||||
// the object to the wrapping Create activity.
|
||||
// Again, presumably if it does not already exist.
|
||||
for _, attributedToMap := range objectAttributedToIds {
|
||||
for k, v := range attributedToMap {
|
||||
if _, ok := createActorIds[k]; !ok {
|
||||
|
@ -436,6 +431,12 @@ func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool) f
|
|||
}
|
||||
}
|
||||
}
|
||||
// As such, a server SHOULD copy any recipients of the Create activity to its
|
||||
// object upon initial distribution, and likewise with copying recipients from
|
||||
// the object to the wrapping Create activity.
|
||||
if err := f.sameRecipients(c); err != nil {
|
||||
return err
|
||||
}
|
||||
// Create requires the client application to persist the 'object' that
|
||||
// was created.
|
||||
for _, o := range obj {
|
||||
|
@ -443,6 +444,13 @@ func (f *federator) handleClientCreate(ctx context.Context, deliverable *bool) f
|
|||
return err
|
||||
}
|
||||
}
|
||||
// Persist the above changes in the outbox
|
||||
var err error
|
||||
*toAddToOutbox = make(map[string]interface{})
|
||||
*toAddToOutbox, err = c.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.ClientCallbacker.Create(ctx, s)
|
||||
}
|
||||
}
|
||||
|
|
202
pub/fed_test.go
202
pub/fed_test.go
|
@ -34,34 +34,36 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
iri *url.URL
|
||||
noteIRI *url.URL
|
||||
noteActivityIRI *url.URL
|
||||
updateActivityIRI *url.URL
|
||||
testNewIRI *url.URL
|
||||
sallyIRI *url.URL
|
||||
sallyIRIInbox *url.URL
|
||||
sallyActor *vocab.Person
|
||||
sallyActorJSON []byte
|
||||
samIRI *url.URL
|
||||
samIRIInbox *url.URL
|
||||
samIRIFollowers *url.URL
|
||||
samActor *vocab.Person
|
||||
samActorJSON []byte
|
||||
testNote *vocab.Note
|
||||
testSingleOrderedCollection *vocab.OrderedCollection
|
||||
testCreateNote *vocab.Create
|
||||
testUpdateNote *vocab.Update
|
||||
testDeleteNote *vocab.Delete
|
||||
testTombstoneNote *vocab.Tombstone
|
||||
testFollow *vocab.Follow
|
||||
testAcceptNote *vocab.Accept
|
||||
testAcceptFollow *vocab.Accept
|
||||
testRejectFollow *vocab.Reject
|
||||
testAddNote *vocab.Add
|
||||
testRemoveNote *vocab.Remove
|
||||
testLikeNote *vocab.Like
|
||||
testUndoLike *vocab.Undo
|
||||
iri *url.URL
|
||||
noteIRI *url.URL
|
||||
noteActivityIRI *url.URL
|
||||
updateActivityIRI *url.URL
|
||||
testNewIRI *url.URL
|
||||
sallyIRI *url.URL
|
||||
sallyIRIInbox *url.URL
|
||||
sallyActor *vocab.Person
|
||||
sallyActorJSON []byte
|
||||
samIRI *url.URL
|
||||
samIRIInbox *url.URL
|
||||
samIRIFollowers *url.URL
|
||||
samActor *vocab.Person
|
||||
samActorJSON []byte
|
||||
testNote *vocab.Note
|
||||
testSingleOrderedCollection *vocab.OrderedCollection
|
||||
testCreateNote *vocab.Create
|
||||
testUpdateNote *vocab.Update
|
||||
testDeleteNote *vocab.Delete
|
||||
testTombstoneNote *vocab.Tombstone
|
||||
testFollow *vocab.Follow
|
||||
testAcceptNote *vocab.Accept
|
||||
testAcceptFollow *vocab.Accept
|
||||
testRejectFollow *vocab.Reject
|
||||
testAddNote *vocab.Add
|
||||
testRemoveNote *vocab.Remove
|
||||
testLikeNote *vocab.Like
|
||||
testUndoLike *vocab.Undo
|
||||
testClientExpectedNote *vocab.Note
|
||||
testClientExpectedCreateNote *vocab.Create
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -207,6 +209,19 @@ func init() {
|
|||
testUndoLike.AddActorObject(sallyActor)
|
||||
testUndoLike.AddObject(testLikeNote)
|
||||
testUndoLike.AddToObject(samActor)
|
||||
|
||||
testClientExpectedNote = &vocab.Note{}
|
||||
testClientExpectedNote.SetId(*noteIRI)
|
||||
testClientExpectedNote.AddNameString(noteName)
|
||||
testClientExpectedNote.AddContentString("This is a simple note")
|
||||
testClientExpectedNote.AddAttributedToObject(sallyActor)
|
||||
testClientExpectedNote.AddToObject(samActor)
|
||||
testClientExpectedCreateNote = &vocab.Create{}
|
||||
testClientExpectedCreateNote.SetId(*testNewIRI)
|
||||
testClientExpectedCreateNote.AddSummaryString("Sally created a note")
|
||||
testClientExpectedCreateNote.AddActorObject(sallyActor)
|
||||
testClientExpectedCreateNote.AddObject(testClientExpectedNote)
|
||||
testClientExpectedCreateNote.AddToObject(samActor)
|
||||
}
|
||||
|
||||
func Must(l *time.Location, e error) *time.Location {
|
||||
|
@ -752,9 +767,9 @@ func TestSocialPubber_PostOutbox(t *testing.T) {
|
|||
app.set = func(c context.Context, o PubObject) error {
|
||||
gotSet++
|
||||
if gotSet == 1 {
|
||||
gotSetOutbox = o
|
||||
} else if gotSet == 2 {
|
||||
gotSetCreateObject = o
|
||||
} else if gotSet == 2 {
|
||||
gotSetOutbox = o
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1038,9 +1053,9 @@ func TestPubber_PostOutbox(t *testing.T) {
|
|||
app.set = func(c context.Context, o PubObject) error {
|
||||
gotSet++
|
||||
if gotSet == 1 {
|
||||
gotSetOutbox = o
|
||||
} else if gotSet == 2 {
|
||||
gotSetCreateObject = o
|
||||
} else if gotSet == 2 {
|
||||
gotSetOutbox = o
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -2892,23 +2907,130 @@ func TestPostOutbox_RequiresTarget(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPostOutbox_Create_CopyToAttributedTo(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostOutbox_Create_CopyRecipientsToObject(t *testing.T) {
|
||||
// TODO: Implement
|
||||
app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t)
|
||||
PreparePostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p)
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))
|
||||
var gotCallbackObject *streams.Create
|
||||
socialCb.create = func(c context.Context, s *streams.Create) error {
|
||||
gotCallbackObject = s
|
||||
return nil
|
||||
}
|
||||
handled, err := p.PostOutbox(context.Background(), resp, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !handled {
|
||||
t.Fatalf("expected handled, got !handled")
|
||||
} else if e := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedCreateNote); e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostOutbox_Create_SetCreatedObject(t *testing.T) {
|
||||
// TODO: Implement
|
||||
app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t)
|
||||
PreparePostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p)
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))
|
||||
socialCb.create = func(c context.Context, s *streams.Create) error {
|
||||
return nil
|
||||
}
|
||||
gotSet := 0
|
||||
var gotSetOutbox PubObject
|
||||
var gotSetCreate PubObject
|
||||
app.set = func(c context.Context, o PubObject) error {
|
||||
gotSet++
|
||||
if gotSet == 1 {
|
||||
gotSetCreate = o
|
||||
} else {
|
||||
gotSetOutbox = o
|
||||
}
|
||||
return nil
|
||||
}
|
||||
handled, err := p.PostOutbox(context.Background(), resp, req)
|
||||
expectedOutbox := &vocab.OrderedCollection{}
|
||||
expectedOutbox.AddType("OrderedCollection")
|
||||
expectedOutbox.AddOrderedItemsObject(testClientExpectedCreateNote)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !handled {
|
||||
t.Fatalf("expected handled, got !handled")
|
||||
} else if gotSet != 2 {
|
||||
t.Fatalf("expected %d, got %d", 2, gotSet)
|
||||
} else if err := PubObjectEquals(gotSetCreate, testClientExpectedNote); err != nil {
|
||||
t.Fatalf("unexpected callback object: %s", err)
|
||||
} else if err := PubObjectEquals(gotSetOutbox, expectedOutbox); err != nil {
|
||||
t.Fatalf("unexpected callback object: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostOutbox_Create_CallsCallback(t *testing.T) {
|
||||
// TODO: Implement
|
||||
app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t)
|
||||
PreparePostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p)
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))
|
||||
gotCallback := 0
|
||||
var gotCallbackObject *streams.Create
|
||||
socialCb.create = func(c context.Context, s *streams.Create) error {
|
||||
gotCallback++
|
||||
gotCallbackObject = s
|
||||
return nil
|
||||
}
|
||||
handled, err := p.PostOutbox(context.Background(), resp, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !handled {
|
||||
t.Fatalf("expected handled, got !handled")
|
||||
} else if gotCallback != 1 {
|
||||
t.Fatalf("expected %d, got %d", 1, gotCallback)
|
||||
} else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedCreateNote); err != nil {
|
||||
t.Fatalf("unexpected callback object: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostOutbox_Create_IsDelivered(t *testing.T) {
|
||||
// TODO: Implement
|
||||
app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t)
|
||||
PreparePostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p)
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))
|
||||
socialCb.create = func(c context.Context, s *streams.Create) error {
|
||||
return nil
|
||||
}
|
||||
gotHttpDo := 0
|
||||
var httpDeliveryRequest *http.Request
|
||||
httpClient.do = func(req *http.Request) (*http.Response, error) {
|
||||
gotHttpDo++
|
||||
if gotHttpDo == 1 {
|
||||
actorResp := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)),
|
||||
}
|
||||
return actorResp, nil
|
||||
} else if gotHttpDo == 2 {
|
||||
actorResp := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)),
|
||||
}
|
||||
return actorResp, nil
|
||||
} else if gotHttpDo == 3 {
|
||||
httpDeliveryRequest = req
|
||||
okResp := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})),
|
||||
}
|
||||
return okResp, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
handled, err := p.PostOutbox(context.Background(), resp, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !handled {
|
||||
t.Fatalf("expected handled, got !handled")
|
||||
} else if httpDeliveryRequest.Method != "POST" {
|
||||
t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method)
|
||||
} else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString {
|
||||
t.Fatalf("expected %s, got %s", samIRIInboxString, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostOutbox_Update_OverwriteUpdatedFields(t *testing.T) {
|
||||
|
|
301
pub/internal.go
301
pub/internal.go
|
@ -173,6 +173,307 @@ func (f *federator) wrapInCreate(o vocab.ObjectType, actor url.URL) *vocab.Creat
|
|||
return c
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// If there is any disagreement between the activity and an object, we default
|
||||
// to a no-op.
|
||||
func (f *federator) sameRecipients(a vocab.ActivityType) error {
|
||||
// First, map recipients for each object and the activity.
|
||||
to := make([]map[string]interface{}, a.ObjectLen())
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
to[i] = make(map[string]interface{})
|
||||
if !a.IsObject(i) {
|
||||
return fmt.Errorf("sameRecipients does not support 'to' object IRIs on Activities")
|
||||
}
|
||||
o := a.GetObject(i)
|
||||
for j := 0; j < o.ToLen(); j++ {
|
||||
if o.IsToObject(j) {
|
||||
id := o.GetToObject(j).GetId()
|
||||
to[i][(&id).String()] = o.GetToObject(j)
|
||||
} else if o.IsToLink(j) {
|
||||
id := o.GetToLink(j).GetHref()
|
||||
to[i][(&id).String()] = o.GetToLink(j)
|
||||
} else if o.IsToIRI(j) {
|
||||
id := o.GetToIRI(j)
|
||||
to[i][(&id).String()] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
toActivity := make(map[string]interface{})
|
||||
for i := 0; i < a.ToLen(); i++ {
|
||||
if a.IsToObject(i) {
|
||||
id := a.GetToObject(i).GetId()
|
||||
toActivity[(&id).String()] = a.GetToObject(i)
|
||||
} else if a.IsToLink(i) {
|
||||
id := a.GetToLink(i).GetHref()
|
||||
toActivity[(&id).String()] = a.GetToLink(i)
|
||||
} else if a.IsToIRI(i) {
|
||||
id := a.GetToIRI(i)
|
||||
toActivity[(&id).String()] = id
|
||||
}
|
||||
}
|
||||
bto := make([]map[string]interface{}, a.ObjectLen())
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
bto[i] = make(map[string]interface{})
|
||||
if !a.IsObject(i) {
|
||||
return fmt.Errorf("sameRecipients does not support 'bto' object IRIs on Activities")
|
||||
}
|
||||
o := a.GetObject(i)
|
||||
for j := 0; j < o.BtoLen(); j++ {
|
||||
if o.IsBtoObject(j) {
|
||||
id := o.GetBtoObject(j).GetId()
|
||||
bto[i][(&id).String()] = o.GetBtoObject(j)
|
||||
} else if o.IsBtoLink(j) {
|
||||
id := o.GetBtoLink(j).GetHref()
|
||||
bto[i][(&id).String()] = o.GetBtoLink(j)
|
||||
} else if o.IsBtoIRI(j) {
|
||||
id := o.GetBtoIRI(j)
|
||||
bto[i][(&id).String()] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
btoActivity := make(map[string]interface{})
|
||||
for i := 0; i < a.BtoLen(); i++ {
|
||||
if a.IsBtoObject(i) {
|
||||
id := a.GetBtoObject(i).GetId()
|
||||
btoActivity[(&id).String()] = a.GetBtoObject(i)
|
||||
} else if a.IsBtoLink(i) {
|
||||
id := a.GetBtoLink(i).GetHref()
|
||||
btoActivity[(&id).String()] = a.GetBtoLink(i)
|
||||
} else if a.IsBtoIRI(i) {
|
||||
id := a.GetBtoIRI(i)
|
||||
btoActivity[(&id).String()] = id
|
||||
}
|
||||
}
|
||||
cc := make([]map[string]interface{}, a.ObjectLen())
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
cc[i] = make(map[string]interface{})
|
||||
if !a.IsObject(i) {
|
||||
return fmt.Errorf("sameRecipients does not support 'cc' object IRIs on Activities")
|
||||
}
|
||||
o := a.GetObject(i)
|
||||
for j := 0; j < o.CcLen(); j++ {
|
||||
if o.IsCcObject(j) {
|
||||
id := o.GetCcObject(j).GetId()
|
||||
cc[i][(&id).String()] = o.GetCcObject(j)
|
||||
} else if o.IsCcLink(j) {
|
||||
id := o.GetCcLink(j).GetHref()
|
||||
cc[i][(&id).String()] = o.GetCcLink(j)
|
||||
} else if o.IsCcIRI(j) {
|
||||
id := o.GetCcIRI(j)
|
||||
cc[i][(&id).String()] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
ccActivity := make(map[string]interface{})
|
||||
for i := 0; i < a.CcLen(); i++ {
|
||||
if a.IsCcObject(i) {
|
||||
id := a.GetCcObject(i).GetId()
|
||||
ccActivity[(&id).String()] = a.GetCcObject(i)
|
||||
} else if a.IsCcLink(i) {
|
||||
id := a.GetCcLink(i).GetHref()
|
||||
ccActivity[(&id).String()] = a.GetCcLink(i)
|
||||
} else if a.IsCcIRI(i) {
|
||||
id := a.GetCcIRI(i)
|
||||
ccActivity[(&id).String()] = id
|
||||
}
|
||||
}
|
||||
bcc := make([]map[string]interface{}, a.ObjectLen())
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
bcc[i] = make(map[string]interface{})
|
||||
if !a.IsObject(i) {
|
||||
return fmt.Errorf("sameRecipients does not support 'bcc' object IRIs on Activities")
|
||||
}
|
||||
o := a.GetObject(i)
|
||||
for j := 0; j < o.BccLen(); j++ {
|
||||
if o.IsBccObject(j) {
|
||||
id := o.GetBccObject(j).GetId()
|
||||
bcc[i][(&id).String()] = o.GetBccObject(j)
|
||||
} else if o.IsBccLink(j) {
|
||||
id := o.GetBccLink(j).GetHref()
|
||||
bcc[i][(&id).String()] = o.GetBccLink(j)
|
||||
} else if o.IsBccIRI(j) {
|
||||
id := o.GetBccIRI(j)
|
||||
bcc[i][(&id).String()] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
bccActivity := make(map[string]interface{})
|
||||
for i := 0; i < a.BccLen(); i++ {
|
||||
if a.IsBccObject(i) {
|
||||
id := a.GetBccObject(i).GetId()
|
||||
bccActivity[(&id).String()] = a.GetBccObject(i)
|
||||
} else if a.IsBccLink(i) {
|
||||
id := a.GetBccLink(i).GetHref()
|
||||
bccActivity[(&id).String()] = a.GetBccLink(i)
|
||||
} else if a.IsBccIRI(i) {
|
||||
id := a.GetBccIRI(i)
|
||||
bccActivity[(&id).String()] = id
|
||||
}
|
||||
}
|
||||
audience := make([]map[string]interface{}, a.ObjectLen())
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
audience[i] = make(map[string]interface{})
|
||||
if !a.IsObject(i) {
|
||||
return fmt.Errorf("sameRecipients does not support 'audience' object IRIs on Activities")
|
||||
}
|
||||
o := a.GetObject(i)
|
||||
for j := 0; j < o.AudienceLen(); j++ {
|
||||
if o.IsAudienceObject(j) {
|
||||
id := o.GetAudienceObject(j).GetId()
|
||||
audience[i][(&id).String()] = o.GetAudienceObject(j)
|
||||
} else if o.IsAudienceLink(j) {
|
||||
id := o.GetAudienceLink(j).GetHref()
|
||||
audience[i][(&id).String()] = o.GetAudienceLink(j)
|
||||
} else if o.IsAudienceIRI(j) {
|
||||
id := o.GetAudienceIRI(j)
|
||||
audience[i][(&id).String()] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
audienceActivity := make(map[string]interface{})
|
||||
for i := 0; i < a.AudienceLen(); i++ {
|
||||
if a.IsAudienceObject(i) {
|
||||
id := a.GetAudienceObject(i).GetId()
|
||||
audienceActivity[(&id).String()] = a.GetAudienceObject(i)
|
||||
} else if a.IsAudienceLink(i) {
|
||||
id := a.GetAudienceLink(i).GetHref()
|
||||
audienceActivity[(&id).String()] = a.GetAudienceLink(i)
|
||||
} else if a.IsAudienceIRI(i) {
|
||||
id := a.GetAudienceIRI(i)
|
||||
audienceActivity[(&id).String()] = id
|
||||
}
|
||||
}
|
||||
// Next, add activity recipients to all objects if not already present
|
||||
for k, v := range toActivity {
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
if _, ok := to[i][k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.GetObject(i).AddToObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.GetObject(i).AddToLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.GetObject(i).AddToIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range btoActivity {
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
if _, ok := bto[i][k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.GetObject(i).AddBtoObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.GetObject(i).AddBtoLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.GetObject(i).AddBtoIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range ccActivity {
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
if _, ok := cc[i][k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.GetObject(i).AddCcObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.GetObject(i).AddCcLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.GetObject(i).AddCcIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range bccActivity {
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
if _, ok := bcc[i][k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.GetObject(i).AddBccObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.GetObject(i).AddBccLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.GetObject(i).AddBccIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range audienceActivity {
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
if _, ok := audience[i][k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.GetObject(i).AddAudienceObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.GetObject(i).AddAudienceLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.GetObject(i).AddAudienceIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, add all the objects' recipients to the activity if not
|
||||
// already present.
|
||||
for i := 0; i < a.ObjectLen(); i++ {
|
||||
for k, v := range to[i] {
|
||||
if _, ok := toActivity[k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.AddToObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.AddToLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.AddToIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range bto[i] {
|
||||
if _, ok := btoActivity[k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.AddBtoObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.AddBtoLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.AddBtoIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range cc[i] {
|
||||
if _, ok := ccActivity[k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.AddCcObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.AddCcLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.AddCcIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range bcc[i] {
|
||||
if _, ok := bccActivity[k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.AddBccObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.AddBccLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.AddBccIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range audience[i] {
|
||||
if _, ok := audienceActivity[k]; !ok {
|
||||
if vObj, ok := v.(vocab.ObjectType); ok {
|
||||
a.AddAudienceObject(vObj)
|
||||
} else if vLink, ok := v.(vocab.LinkType); ok {
|
||||
a.AddAudienceLink(vLink)
|
||||
} else if vIRI, ok := v.(url.URL); ok {
|
||||
a.AddAudienceIRI(vIRI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: (Section 7) HTTP caching mechanisms [RFC7234] SHOULD be respected when appropriate, both when receiving responses from other servers as well as sending responses to other servers.
|
||||
|
||||
// deliver will complete the peer-to-peer sending of a federated message to
|
||||
|
|
読み込み中…
新しいイシューから参照