Support likes, liked, blocking, auto-accept/reject follows.
このコミットが含まれているのは:
コミット
07a04262d9
128
pub/fed.go
128
pub/fed.go
|
@ -23,32 +23,8 @@ var (
|
||||||
// TODO: Helper http Handler for serving Tombstone objects
|
// TODO: Helper http Handler for serving Tombstone objects
|
||||||
// TODO: Helper http Handler for serving deleted objects
|
// TODO: Helper http Handler for serving deleted objects
|
||||||
|
|
||||||
// FederateApp is provided by users of this library and designed to handle
|
// TODO: Authorization client-to-server.
|
||||||
// receiving messages from ActivityPub servers through the Federative API.
|
// TODO: Authenticate server-to-server deliveries.
|
||||||
type FederateApp interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callbacker provides an Application hooks into the lifecycle of the
|
|
||||||
// ActivityPub processes for both client-to-server and server-to-server
|
|
||||||
// interactions. These callbacks are called after their spec-compliant actions
|
|
||||||
// are completed, but before inbox forwarding and before delivery.
|
|
||||||
//
|
|
||||||
// Note that modifying the ActivityStream objects in a callback may cause
|
|
||||||
// unintentionally non-standard behavior if modifying core attributes, but
|
|
||||||
// otherwise affords clients powerful flexibility. Use responsibly.
|
|
||||||
type Callbacker interface {
|
|
||||||
Create(c context.Context, s *streams.Create) error
|
|
||||||
Update(c context.Context, s *streams.Update) error
|
|
||||||
Delete(c context.Context, s *streams.Delete) error
|
|
||||||
Add(c context.Context, s *streams.Add) error
|
|
||||||
Remove(c context.Context, s *streams.Remove) error
|
|
||||||
Like(c context.Context, s *streams.Like) error
|
|
||||||
Block(c context.Context, s *streams.Block) error
|
|
||||||
Follow(c context.Context, s *streams.Follow) error
|
|
||||||
Undo(c context.Context, s *streams.Undo) error
|
|
||||||
Accept(c context.Context, s *streams.Accept) error
|
|
||||||
Reject(c context.Context, s *streams.Reject) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type federator struct {
|
type federator struct {
|
||||||
// Clock determines the time of this federator.
|
// Clock determines the time of this federator.
|
||||||
|
@ -131,6 +107,29 @@ func (f *federator) PostInbox(c context.Context, w http.ResponseWriter, r *http.
|
||||||
if err = json.Unmarshal(b, &m); err != nil {
|
if err = json.Unmarshal(b, &m); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
ao, err := getActorObject(m)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
var iris []url.URL
|
||||||
|
for i := 0; i < ao.ActorLen(); i++ {
|
||||||
|
if ao.IsActorObject(i) {
|
||||||
|
obj := ao.GetActorObject(i)
|
||||||
|
if obj.HasId() {
|
||||||
|
iris = append(iris, obj.GetId())
|
||||||
|
}
|
||||||
|
} else if ao.IsActorLink(i) {
|
||||||
|
l := ao.GetActorLink(i)
|
||||||
|
if l.HasHref() {
|
||||||
|
iris = append(iris, l.GetHref())
|
||||||
|
}
|
||||||
|
} else if ao.IsActorIRI(i) {
|
||||||
|
iris = append(iris, ao.GetActorIRI(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = f.FederateApp.Unblocked(c, iris); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
if err = f.getPostInboxResolver(c).Deserialize(m); err != nil {
|
if err = f.getPostInboxResolver(c).Deserialize(m); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
@ -233,24 +232,9 @@ func (f *federator) PostOutbox(c context.Context, w http.ResponseWriter, r *http
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
recipients, err := f.prepare(obj)
|
if err := f.deliver(obj); err != nil {
|
||||||
if err != nil {
|
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
m, err := obj.Serialize()
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
m["@context"] = "https://www.w3.org/ns/activitystreams"
|
|
||||||
b, err := json.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
for _, to := range recipients {
|
|
||||||
f.pool.Do(b, to, func(b []byte, u url.URL) error {
|
|
||||||
return postToOutbox(f.Client, b, u, f.Agent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
w.Header().Set("Location", newId.String())
|
w.Header().Set("Location", newId.String())
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
@ -285,8 +269,16 @@ func (f *federator) GetOutbox(c context.Context, w http.ResponseWriter, r *http.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *federator) addToOutbox(c context.Context, m map[string]interface{}) error {
|
func (f *federator) addToOutbox(c context.Context, m map[string]interface{}) error {
|
||||||
// TODO
|
outbox, err := f.SocialApp.GetOutbox(c)
|
||||||
return nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
activity, err := toAnyActivity(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outbox.AddOrderedItemsObject(activity)
|
||||||
|
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) *streams.Resolver {
|
||||||
|
@ -644,14 +636,16 @@ func (f *federator) handleClientRemove(c context.Context, deliverable *bool) fun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *federator) handleClientLike(c context.Context, deliverable *bool) func(s *streams.Like) error {
|
func (f *federator) handleClientLike(ctx context.Context, deliverable *bool) func(s *streams.Like) error {
|
||||||
return func(s *streams.Like) error {
|
return func(s *streams.Like) error {
|
||||||
*deliverable = true
|
*deliverable = true
|
||||||
if s.LenObject() == 0 {
|
if s.LenObject() == 0 {
|
||||||
return ErrObjectRequired
|
return ErrObjectRequired
|
||||||
}
|
}
|
||||||
// TODO: The server SHOULD add the object to the actor's liked Collection.
|
if err := f.addToAllActorLikedCollection(ctx, s.Raw()); err != nil {
|
||||||
return f.ClientCallbacker.Like(c, s)
|
return err
|
||||||
|
}
|
||||||
|
return f.ClientCallbacker.Like(ctx, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,7 +655,7 @@ func (f *federator) handleClientUndo(c context.Context, deliverable *bool) func(
|
||||||
if s.LenObject() == 0 {
|
if s.LenObject() == 0 {
|
||||||
return ErrObjectRequired
|
return ErrObjectRequired
|
||||||
}
|
}
|
||||||
// TODO: Support common forms of undo natively.
|
// TODO: Determine if we can support common forms of undo natively.
|
||||||
return f.ClientCallbacker.Undo(c, s)
|
return f.ClientCallbacker.Undo(c, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,7 +666,6 @@ func (f *federator) handleClientBlock(c context.Context, deliverable *bool) func
|
||||||
if s.LenObject() == 0 {
|
if s.LenObject() == 0 {
|
||||||
return ErrObjectRequired
|
return ErrObjectRequired
|
||||||
}
|
}
|
||||||
// TODO: Add to blocked app.
|
|
||||||
return f.ClientCallbacker.Block(c, s)
|
return f.ClientCallbacker.Block(c, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -761,11 +754,31 @@ func (f *federator) handleDelete(c context.Context) func(s *streams.Delete) erro
|
||||||
|
|
||||||
func (f *federator) handleFollow(c context.Context) func(s *streams.Follow) error {
|
func (f *federator) handleFollow(c context.Context) func(s *streams.Follow) error {
|
||||||
return func(s *streams.Follow) error {
|
return func(s *streams.Follow) error {
|
||||||
// TODO: Implement.
|
// Permit either human-triggered or automatically triggering
|
||||||
// Follow means the client application SHOULD reply with an 'Accept' or
|
// 'Accept'/'Reject'.
|
||||||
// 'Reject' ActivityStream with the 'Follow' as the 'object' and deliver
|
todo := f.FederateApp.OnFollow(c, s)
|
||||||
// it to the 'actor' of the 'Follow'. This can be human-triggered or
|
if todo != DoNothing {
|
||||||
// automatically triggered.
|
var activity vocab.ActivityType
|
||||||
|
if todo == AutomaticAccept {
|
||||||
|
activity = &vocab.Accept{}
|
||||||
|
} else if todo == AutomaticReject {
|
||||||
|
activity = &vocab.Reject{}
|
||||||
|
}
|
||||||
|
raw := s.Raw()
|
||||||
|
activity.AddObject(raw)
|
||||||
|
for i := 0; i < raw.ActorLen(); i++ {
|
||||||
|
if raw.IsActorObject(i) {
|
||||||
|
activity.AddToObject(raw.GetActorObject(i))
|
||||||
|
} else if raw.IsActorLink(i) {
|
||||||
|
activity.AddToLink(raw.GetActorLink(i))
|
||||||
|
} else if raw.IsActorIRI(i) {
|
||||||
|
activity.AddToIRI(raw.GetActorIRI(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := f.deliver(activity); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return f.ServerCallbacker.Follow(c, s)
|
return f.ServerCallbacker.Follow(c, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,7 +795,6 @@ func (f *federator) handleAccept(c context.Context) func(s *streams.Accept) erro
|
||||||
|
|
||||||
func (f *federator) handleReject(c context.Context) func(s *streams.Reject) error {
|
func (f *federator) handleReject(c context.Context) func(s *streams.Reject) error {
|
||||||
return func(s *streams.Reject) error {
|
return func(s *streams.Reject) error {
|
||||||
// TODO: Implement.
|
|
||||||
// Reject can be client application specific. However, if this 'Reject'
|
// Reject can be client application specific. However, if this 'Reject'
|
||||||
// is in response to a 'Follow' then the client MUST NOT go forward with
|
// is in response to a 'Follow' then the client MUST NOT go forward with
|
||||||
// adding the 'actor' to the original 'actor's 'following' collection
|
// adding the 'actor' to the original 'actor's 'following' collection
|
||||||
|
@ -811,15 +823,15 @@ func (f *federator) handleRemove(c context.Context) func(s *streams.Remove) erro
|
||||||
|
|
||||||
func (f *federator) handleLike(c context.Context) func(s *streams.Like) error {
|
func (f *federator) handleLike(c context.Context) func(s *streams.Like) error {
|
||||||
return func(s *streams.Like) error {
|
return func(s *streams.Like) error {
|
||||||
// TODO: Implement.
|
if err := f.addToAllLikesCollections(c, s.Raw()); err != nil {
|
||||||
// Like triggers adding the like to an object's `like` collection.
|
return err
|
||||||
|
}
|
||||||
return f.ServerCallbacker.Like(c, s)
|
return f.ServerCallbacker.Like(c, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *federator) handleUndo(c context.Context) func(s *streams.Undo) error {
|
func (f *federator) handleUndo(c context.Context) func(s *streams.Undo) error {
|
||||||
return func(s *streams.Undo) error {
|
return func(s *streams.Undo) error {
|
||||||
// TODO: Implement.
|
|
||||||
// Undo negates a previous action. The 'actor' on the 'Undo' MUST be the
|
// Undo negates a previous action. The 'actor' on the 'Undo' MUST be the
|
||||||
// same as the 'actor' on the Activity being undone, and the client
|
// same as the 'actor' on the Activity being undone, and the client
|
||||||
// application is responsible for enforcing this. Note that 'Undo'-ing
|
// application is responsible for enforcing this. Note that 'Undo'-ing
|
||||||
|
|
|
@ -3,6 +3,7 @@ package pub
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/go-fed/activity/vocab"
|
"github.com/go-fed/activity/vocab"
|
||||||
|
"github.com/go-fed/activity/streams"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
@ -67,6 +68,76 @@ type SocialApp interface {
|
||||||
// CanRemove returns true if the provided object is allowed to be
|
// CanRemove returns true if the provided object is allowed to be
|
||||||
// removed from the given target collection.
|
// removed from the given target collection.
|
||||||
CanRemove(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool
|
CanRemove(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool
|
||||||
|
// GetOutbox gets the outbox of an actor.
|
||||||
|
GetOutbox(c context.Context) (vocab.OrderedCollectionType, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FollowResponse instructs how to proceed upon immediately receiving a request
|
||||||
|
// to follow.
|
||||||
|
type FollowResponse int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AutomaticAccept FollowResponse = iota
|
||||||
|
AutomaticReject
|
||||||
|
DoNothing
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callbacker provides an Application hooks into the lifecycle of the
|
||||||
|
// ActivityPub processes for both client-to-server and server-to-server
|
||||||
|
// interactions. These callbacks are called after their spec-compliant actions
|
||||||
|
// are completed, but before inbox forwarding and before delivery.
|
||||||
|
//
|
||||||
|
// Note that modifying the ActivityStream objects in a callback may cause
|
||||||
|
// unintentionally non-standard behavior if modifying core attributes, but
|
||||||
|
// otherwise affords clients powerful flexibility. Use responsibly.
|
||||||
|
type Callbacker interface {
|
||||||
|
// Create Activity callback.
|
||||||
|
Create(c context.Context, s *streams.Create) error
|
||||||
|
// Update Activity callback.
|
||||||
|
Update(c context.Context, s *streams.Update) error
|
||||||
|
// Delete Activity callback.
|
||||||
|
Delete(c context.Context, s *streams.Delete) error
|
||||||
|
// Add Activity callback.
|
||||||
|
Add(c context.Context, s *streams.Add) error
|
||||||
|
// Remove Activity callback.
|
||||||
|
Remove(c context.Context, s *streams.Remove) error
|
||||||
|
// Like Activity callback.
|
||||||
|
Like(c context.Context, s *streams.Like) error
|
||||||
|
// Block Activity callback. By default, this implmentation does not
|
||||||
|
// dictate how blocking should be implemented, so it is up to the
|
||||||
|
// application to enforce this by implementing the FederateApp
|
||||||
|
// interface.
|
||||||
|
Block(c context.Context, s *streams.Block) error
|
||||||
|
// Follow Activity callback. In the special case of server-to-server
|
||||||
|
// delivery of a Follow activity, this implementation supports the
|
||||||
|
// option of automatically replying with an 'Accept', 'Reject', or
|
||||||
|
// waiting for human interaction as provided in the FederateApp
|
||||||
|
// interface.
|
||||||
|
Follow(c context.Context, s *streams.Follow) error
|
||||||
|
// Undo Activity callback. It is up to the client to provide support
|
||||||
|
// for all 'Undo' operations; this implementation does not attempt to
|
||||||
|
// provide a generic implementation.
|
||||||
|
Undo(c context.Context, s *streams.Undo) error
|
||||||
|
// Accept Activity callback.
|
||||||
|
Accept(c context.Context, s *streams.Accept) error
|
||||||
|
// Reject Activity callback.
|
||||||
|
Reject(c context.Context, s *streams.Reject) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// FederateApp is provided by users of this library and designed to handle
|
||||||
|
// receiving messages from ActivityPub servers through the Federative API.
|
||||||
|
type FederateApp interface {
|
||||||
|
// OnFollow determines whether to take any automatic reactions in
|
||||||
|
// response to this follow.
|
||||||
|
OnFollow(c context.Context, s *streams.Follow) FollowResponse
|
||||||
|
// Unblocked should return an error if the provided actor ids are not
|
||||||
|
// able to interact with this particular end user due to being blocked
|
||||||
|
// or other application-specific logic. This error is passed
|
||||||
|
// transparently back to the request thread via PostInbox.
|
||||||
|
//
|
||||||
|
// If nil error is returned, then the received activity is processed as
|
||||||
|
// a normal unblocked interaction.
|
||||||
|
Unblocked(c context.Context, actorIRIs []url.URL) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// PubObject is an ActivityPub Object.
|
// PubObject is an ActivityPub Object.
|
||||||
|
|
171
pub/internal.go
171
pub/internal.go
|
@ -2,6 +2,7 @@ package pub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-fed/activity/streams"
|
"github.com/go-fed/activity/streams"
|
||||||
|
@ -168,6 +169,30 @@ func (f *federator) wrapInCreate(o vocab.ObjectType, actor url.URL) *vocab.Creat
|
||||||
|
|
||||||
// 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.
|
// 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
|
||||||
|
// another server.
|
||||||
|
func (f *federator) deliver(obj vocab.ActivityType) error {
|
||||||
|
recipients, err := f.prepare(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m, err := obj.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m["@context"] = "https://www.w3.org/ns/activitystreams"
|
||||||
|
b, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, to := range recipients {
|
||||||
|
f.pool.Do(b, to, func(b []byte, u url.URL) error {
|
||||||
|
return postToOutbox(f.Client, b, u, f.Agent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// prepare takes a deliverableObject and returns a list of the proper recipient
|
// prepare takes a deliverableObject and returns a list of the proper recipient
|
||||||
// target URIs. Additionally, the deliverableObject will have any hidden
|
// target URIs. Additionally, the deliverableObject will have any hidden
|
||||||
// hidden recipients ("bto" and "bcc") stripped from it.
|
// hidden recipients ("bto" and "bcc") stripped from it.
|
||||||
|
@ -836,6 +861,152 @@ func toTombstone(obj vocab.ObjectType, id url.URL, now time.Time) vocab.Tombston
|
||||||
return tomb
|
return tomb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *federator) addToAllActorLikedCollection(ctx context.Context, c vocab.LikeType) error {
|
||||||
|
for i := 0; i < c.ActorLen(); i++ {
|
||||||
|
var actor vocab.ObjectType
|
||||||
|
if c.IsActorObject(i) {
|
||||||
|
actor = c.GetActorObject(i)
|
||||||
|
} else if c.IsActorLink(i) {
|
||||||
|
l := c.GetActorLink(i)
|
||||||
|
if !l.HasHref() {
|
||||||
|
return fmt.Errorf("actor Link href required")
|
||||||
|
}
|
||||||
|
pObj, err := f.App.Get(ctx, l.GetHref())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
actor, ok = pObj.(vocab.ObjectType)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("actor is not vocab.ObjectType")
|
||||||
|
}
|
||||||
|
} else if c.IsActorIRI(i) {
|
||||||
|
iri := c.GetActorIRI(i)
|
||||||
|
pObj, err := f.App.Get(ctx, iri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
actor, ok = pObj.(vocab.ObjectType)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("actor is not vocab.ObjectType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var lc vocab.CollectionType
|
||||||
|
var loc vocab.OrderedCollectionType
|
||||||
|
if actor.IsLikedAnyURI() {
|
||||||
|
pObj, err := f.App.Get(ctx, actor.GetLikedAnyURI())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
if lc, ok = pObj.(vocab.CollectionType); !ok {
|
||||||
|
if loc, ok = pObj.(vocab.OrderedCollectionType); !ok {
|
||||||
|
return fmt.Errorf("actors liked collection not CollectionType nor OrderedCollectionType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if actor.IsLikedCollection() {
|
||||||
|
lc = actor.GetLikedCollection()
|
||||||
|
} else if actor.IsLikedOrderedCollection() {
|
||||||
|
loc = actor.GetLikedOrderedCollection()
|
||||||
|
}
|
||||||
|
for i := 0; i < c.ObjectLen(); i++ {
|
||||||
|
if c.IsObjectIRI(i) {
|
||||||
|
if lc != nil {
|
||||||
|
lc.AddItemsIRI(c.GetObjectIRI(i))
|
||||||
|
} else if loc != nil {
|
||||||
|
loc.AddOrderedItemsIRI(c.GetObjectIRI(i))
|
||||||
|
}
|
||||||
|
} else if c.IsObject(i) {
|
||||||
|
if lc != nil {
|
||||||
|
lc.AddItemsObject(c.GetObject(i))
|
||||||
|
} else if loc != nil {
|
||||||
|
loc.AddOrderedItemsObject(c.GetObject(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lc != nil {
|
||||||
|
if err := f.App.Set(ctx, lc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if loc != nil {
|
||||||
|
if err := f.App.Set(ctx, loc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *federator) addToAllLikesCollections(ctx context.Context, c vocab.LikeType) error {
|
||||||
|
for i := 0; i < c.ObjectLen(); i++ {
|
||||||
|
var object vocab.ObjectType
|
||||||
|
if c.IsObject(i) {
|
||||||
|
object = c.GetObject(i)
|
||||||
|
} else if c.IsObjectIRI(i) {
|
||||||
|
iri := c.GetObjectIRI(i)
|
||||||
|
pObj, err := f.App.Get(ctx, iri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
object, ok = pObj.(vocab.ObjectType)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("object is not vocab.ObjectType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var lc vocab.CollectionType
|
||||||
|
var loc vocab.OrderedCollectionType
|
||||||
|
if object.IsLikesAnyURI() {
|
||||||
|
pObj, err := f.App.Get(ctx, object.GetLikesAnyURI())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
if lc, ok = pObj.(vocab.CollectionType); !ok {
|
||||||
|
if loc, ok = pObj.(vocab.OrderedCollectionType); !ok {
|
||||||
|
return fmt.Errorf("object likes collection not CollectionType nor OrderedCollectionType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if object.IsLikesCollection() {
|
||||||
|
lc = object.GetLikesCollection()
|
||||||
|
} else if object.IsLikesOrderedCollection() {
|
||||||
|
loc = object.GetLikesOrderedCollection()
|
||||||
|
}
|
||||||
|
for i := 0; i < c.ActorLen(); i++ {
|
||||||
|
if c.IsActorIRI(i) {
|
||||||
|
if lc != nil {
|
||||||
|
lc.AddItemsIRI(c.GetActorIRI(i))
|
||||||
|
} else if loc != nil {
|
||||||
|
loc.AddOrderedItemsIRI(c.GetActorIRI(i))
|
||||||
|
}
|
||||||
|
} else if c.IsActorObject(i) {
|
||||||
|
if lc != nil {
|
||||||
|
lc.AddItemsObject(c.GetActorObject(i))
|
||||||
|
} else if loc != nil {
|
||||||
|
loc.AddOrderedItemsObject(c.GetActorObject(i))
|
||||||
|
}
|
||||||
|
} else if c.IsActorLink(i) {
|
||||||
|
if lc != nil {
|
||||||
|
lc.AddItemsLink(c.GetActorLink(i))
|
||||||
|
} else if loc != nil {
|
||||||
|
loc.AddOrderedItemsLink(c.GetActorLink(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lc != nil {
|
||||||
|
if err := f.App.Set(ctx, lc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if loc != nil {
|
||||||
|
if err := f.App.Set(ctx, loc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Move this to vocab package.
|
// TODO: Move this to vocab package.
|
||||||
var activityTypes = []string{"Accept", "Add", "Announce", "Arrive", "Block", "Create", "Delete", "Dislike", "Flag", "Follow", "Ignore", "Invite", "Join", "Leave", "Like", "Listen", "Move", "Offer", "Question", "Reject", "Read", "Remove", "TentativeReject", "TentativeAccept", "Travel", "Undo", "Update", "View"}
|
var activityTypes = []string{"Accept", "Add", "Announce", "Arrive", "Block", "Create", "Delete", "Dislike", "Flag", "Follow", "Ignore", "Invite", "Join", "Leave", "Like", "Listen", "Move", "Offer", "Question", "Reject", "Read", "Remove", "TentativeReject", "TentativeAccept", "Travel", "Undo", "Update", "View"}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,12 @@ func ToPubObject(m map[string]interface{}) (t []PubObject, e error) {
|
||||||
return t, e
|
return t, e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getActorObject(m map[string]interface{}) (actorObject, error) {
|
||||||
|
var a actorObject
|
||||||
|
err := toActorResolver(&a).Deserialize(m)
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
|
||||||
func toActorResolver(a *actorObject) *streams.Resolver {
|
func toActorResolver(a *actorObject) *streams.Resolver {
|
||||||
return &streams.Resolver{
|
return &streams.Resolver{
|
||||||
AnyObjectCallback: func(i vocab.ObjectType) error {
|
AnyObjectCallback: func(i vocab.ObjectType) error {
|
||||||
|
|
3432
streams/streams.go
3432
streams/streams.go
ファイル差分が大きすぎるため省略します
差分を読み込み
|
@ -1013,7 +1013,15 @@ var (
|
||||||
URI: propertyBaseURI + "liked",
|
URI: propertyBaseURI + "liked",
|
||||||
Notes: "A link to an [ActivityStreams] collection of objects this actor has liked",
|
Notes: "A link to an [ActivityStreams] collection of objects this actor has liked",
|
||||||
Domain: []DomainReference{{T: objectType}},
|
Domain: []DomainReference{{T: objectType}},
|
||||||
Range: []RangeReference{{V: xsdAnyURIValueType}},
|
Range: []RangeReference{{T: collectionType}, {T: orderedCollectionType}, {V: xsdAnyURIValueType}},
|
||||||
|
Functional: true, // Missing from spec!
|
||||||
|
}
|
||||||
|
likesPropertyType = &PropertyType{
|
||||||
|
Name: "likes",
|
||||||
|
URI: propertyBaseURI + "likes",
|
||||||
|
Notes: "A link to an [ActivityStreams] collection of objects this actor has liked",
|
||||||
|
Domain: []DomainReference{{T: objectType}},
|
||||||
|
Range: []RangeReference{{T: collectionType}, {T: orderedCollectionType}, {V: xsdAnyURIValueType}},
|
||||||
Functional: true, // Missing from spec!
|
Functional: true, // Missing from spec!
|
||||||
}
|
}
|
||||||
streamsPropertyType = &PropertyType{
|
streamsPropertyType = &PropertyType{
|
||||||
|
@ -1164,6 +1172,7 @@ var (
|
||||||
followingPropertyType,
|
followingPropertyType,
|
||||||
followersPropertyType,
|
followersPropertyType,
|
||||||
likedPropertyType,
|
likedPropertyType,
|
||||||
|
likesPropertyType,
|
||||||
streamsPropertyType,
|
streamsPropertyType,
|
||||||
preferredUsernamePropertyType,
|
preferredUsernamePropertyType,
|
||||||
endpointsPropertyType,
|
endpointsPropertyType,
|
||||||
|
@ -1770,6 +1779,7 @@ func init() {
|
||||||
followingPropertyType,
|
followingPropertyType,
|
||||||
followersPropertyType,
|
followersPropertyType,
|
||||||
likedPropertyType,
|
likedPropertyType,
|
||||||
|
likesPropertyType,
|
||||||
streamsPropertyType,
|
streamsPropertyType,
|
||||||
preferredUsernamePropertyType,
|
preferredUsernamePropertyType,
|
||||||
endpointsPropertyType,
|
endpointsPropertyType,
|
||||||
|
|
24336
vocab/vocab.go
24336
vocab/vocab.go
ファイル差分が大きすぎるため省略します
差分を読み込み
読み込み中…
新しいイシューから参照