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 deleted objects
|
||||
|
||||
// FederateApp is provided by users of this library and designed to handle
|
||||
// receiving messages from ActivityPub servers through the Federative API.
|
||||
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
|
||||
}
|
||||
// TODO: Authorization client-to-server.
|
||||
// TODO: Authenticate server-to-server deliveries.
|
||||
|
||||
type federator struct {
|
||||
// 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 {
|
||||
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 {
|
||||
return true, err
|
||||
}
|
||||
|
@ -233,24 +232,9 @@ func (f *federator) PostOutbox(c context.Context, w http.ResponseWriter, r *http
|
|||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
recipients, err := f.prepare(obj)
|
||||
if err != nil {
|
||||
if err := f.deliver(obj); err != nil {
|
||||
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.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 {
|
||||
// TODO
|
||||
return nil
|
||||
outbox, err := f.SocialApp.GetOutbox(c)
|
||||
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 {
|
||||
|
@ -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 {
|
||||
*deliverable = true
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
// TODO: The server SHOULD add the object to the actor's liked Collection.
|
||||
return f.ClientCallbacker.Like(c, s)
|
||||
if err := f.addToAllActorLikedCollection(ctx, s.Raw()); err != nil {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -672,7 +666,6 @@ func (f *federator) handleClientBlock(c context.Context, deliverable *bool) func
|
|||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
// TODO: Add to blocked app.
|
||||
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 {
|
||||
return func(s *streams.Follow) error {
|
||||
// TODO: Implement.
|
||||
// Follow means the client application SHOULD reply with an 'Accept' or
|
||||
// 'Reject' ActivityStream with the 'Follow' as the 'object' and deliver
|
||||
// it to the 'actor' of the 'Follow'. This can be human-triggered or
|
||||
// automatically triggered.
|
||||
// Permit either human-triggered or automatically triggering
|
||||
// 'Accept'/'Reject'.
|
||||
todo := f.FederateApp.OnFollow(c, s)
|
||||
if todo != DoNothing {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
return func(s *streams.Reject) error {
|
||||
// TODO: Implement.
|
||||
// Reject can be client application specific. However, if this 'Reject'
|
||||
// is in response to a 'Follow' then the client MUST NOT go forward with
|
||||
// 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 {
|
||||
return func(s *streams.Like) error {
|
||||
// TODO: Implement.
|
||||
// Like triggers adding the like to an object's `like` collection.
|
||||
if err := f.addToAllLikesCollections(c, s.Raw()); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.ServerCallbacker.Like(c, s)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *federator) handleUndo(c context.Context) 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
|
||||
// same as the 'actor' on the Activity being undone, and the client
|
||||
// application is responsible for enforcing this. Note that 'Undo'-ing
|
||||
|
|
|
@ -3,6 +3,7 @@ package pub
|
|||
import (
|
||||
"context"
|
||||
"github.com/go-fed/activity/vocab"
|
||||
"github.com/go-fed/activity/streams"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
@ -31,7 +32,7 @@ type Clock interface {
|
|||
// modification, allowing implementations to pass-through request-scoped data in
|
||||
// order to properly handle the request.
|
||||
type Application interface {
|
||||
// Get fetches the ActivityStream representation of the given id.
|
||||
// Get fetches the ActivityStream representation of the given id.
|
||||
Get(c context.Context, id url.URL) (PubObject, error)
|
||||
// Set should write or overwrite the value of the provided object for
|
||||
// its 'id'.
|
||||
|
@ -67,6 +68,76 @@ type SocialApp interface {
|
|||
// CanRemove returns true if the provided object is allowed to be
|
||||
// removed from the given target collection.
|
||||
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.
|
||||
|
|
171
pub/internal.go
171
pub/internal.go
|
@ -2,6 +2,7 @@ package pub
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"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.
|
||||
|
||||
// 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
|
||||
// target URIs. Additionally, the deliverableObject will have any hidden
|
||||
// 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
|
||||
}
|
||||
|
||||
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.
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return &streams.Resolver{
|
||||
AnyObjectCallback: func(i vocab.ObjectType) error {
|
||||
|
|
3432
streams/streams.go
3432
streams/streams.go
ファイル差分が大きすぎるため省略します
差分を読み込み
|
@ -1013,7 +1013,15 @@ var (
|
|||
URI: propertyBaseURI + "liked",
|
||||
Notes: "A link to an [ActivityStreams] collection of objects this actor has liked",
|
||||
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!
|
||||
}
|
||||
streamsPropertyType = &PropertyType{
|
||||
|
@ -1164,6 +1172,7 @@ var (
|
|||
followingPropertyType,
|
||||
followersPropertyType,
|
||||
likedPropertyType,
|
||||
likesPropertyType,
|
||||
streamsPropertyType,
|
||||
preferredUsernamePropertyType,
|
||||
endpointsPropertyType,
|
||||
|
@ -1770,6 +1779,7 @@ func init() {
|
|||
followingPropertyType,
|
||||
followersPropertyType,
|
||||
likedPropertyType,
|
||||
likesPropertyType,
|
||||
streamsPropertyType,
|
||||
preferredUsernamePropertyType,
|
||||
endpointsPropertyType,
|
||||
|
|
24336
vocab/vocab.go
24336
vocab/vocab.go
ファイル差分が大きすぎるため省略します
差分を読み込み
読み込み中…
新しいイシューから参照