mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 06:32:25 -05:00
[feature] Support new model of interaction flow for forward compat with v0.21.0 (#4394)
~~Still WIP!~~ This PR allows v0.20.0 of GtS to be forward-compatible with the interaction request / authorization flow that will fully replace the current flow in v0.21.0. Basically, this means we need to recognize LikeRequest, ReplyRequest, and AnnounceRequest, and in response to those requests, deliver either a Reject or an Accept, with the latter pointing towards a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization, respectively. This can then be used by the remote instance to prove to third parties that the interaction has been accepted by the interactee. These Authorization types need to be dereferencable to third parties, so we need to serve them. As well as recognizing the above "polite" interaction request types, we also need to still serve appropriate responses to "impolite" interaction request types, where an instance that's unaware of interaction policies tries to interact with a post by sending a reply, like, or boost directly, without wrapping it in a WhateverRequest type. Doesn't fully close https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 but gets damn near (just gotta update the federating with GtS documentation). Migrations tested on both Postgres and SQLite. Co-authored-by: kim <grufwub@gmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4394 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
parent
33fed81a8d
commit
754b7be9cf
126 changed files with 6637 additions and 1778 deletions
|
|
@ -2402,10 +2402,6 @@ definitions:
|
|||
`reblog` - Someone reblogged / boosted a status.
|
||||
type: string
|
||||
x-go-name: Type
|
||||
uri:
|
||||
description: URI of the Accept or Reject. Only set if accepted_at or rejected_at is set, else omitted.
|
||||
type: string
|
||||
x-go-name: URI
|
||||
title: InteractionRequest represents a pending, approved, or rejected interaction of type favourite, reply, or reblog.
|
||||
type: object
|
||||
x-go-name: InteractionRequest
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -9,7 +9,7 @@ replace github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go
|
|||
replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.38.2-concurrency-workaround
|
||||
|
||||
require (
|
||||
code.superseriousbusiness.org/activity v1.16.0
|
||||
code.superseriousbusiness.org/activity v1.17.0
|
||||
code.superseriousbusiness.org/exif-terminator v0.11.0
|
||||
code.superseriousbusiness.org/httpsig v1.4.0
|
||||
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384
|
||||
|
|
|
|||
4
go.sum
generated
4
go.sum
generated
|
|
@ -1,5 +1,5 @@
|
|||
code.superseriousbusiness.org/activity v1.16.0 h1:6WHpKx2ggkwRlI6lqiK4+VHUdTYRVOcba3fCo1E6wWk=
|
||||
code.superseriousbusiness.org/activity v1.16.0/go.mod h1:BTMWJIAuwDH1w+ieRP5N+T5LipbXjw35U6KZy0V/xdg=
|
||||
code.superseriousbusiness.org/activity v1.17.0 h1:01x4LyvL5fzKgtce+o3mqYbR1O+RaL6j/z7v/B6ivqo=
|
||||
code.superseriousbusiness.org/activity v1.17.0/go.mod h1:BTMWJIAuwDH1w+ieRP5N+T5LipbXjw35U6KZy0V/xdg=
|
||||
code.superseriousbusiness.org/exif-terminator v0.11.0 h1:Hof0MCcsa+1fS17gf86fTTZ8AQnMY9h9kzcc+2C6mVg=
|
||||
code.superseriousbusiness.org/exif-terminator v0.11.0/go.mod h1:9sutT1axa/kSdlPLlRFjCNKmyo/KNx8eX3XZvWBlAEY=
|
||||
code.superseriousbusiness.org/go-jpeg-image-structure/v2 v2.3.0 h1:r9uq8StaSHYKJ8DklR9Xy+E9c40G1Z8yj5TRGi8L6+4=
|
||||
|
|
|
|||
|
|
@ -23,15 +23,18 @@ import (
|
|||
"code.superseriousbusiness.org/activity/pub"
|
||||
)
|
||||
|
||||
// PublicURI returns a fresh copy of the *url.URL version of the
|
||||
// magic ActivityPub URI https://www.w3.org/ns/activitystreams#Public
|
||||
func PublicURI() *url.URL {
|
||||
publicURI, err := url.Parse(pub.PublicActivityPubIRI)
|
||||
// publicIRI is a pre-parsed global public IRI instance.
|
||||
var publicIRI = func() *url.URL {
|
||||
url, err := url.Parse(pub.PublicActivityPubIRI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return publicURI
|
||||
}
|
||||
return url
|
||||
}()
|
||||
|
||||
// PublicIRI returns a fresh copy of the *url.URL version of the
|
||||
// magic ActivityPub URI https://www.w3.org/ns/activitystreams#Public
|
||||
func PublicIRI() *url.URL { var u url.URL; u = *publicIRI; return &u }
|
||||
|
||||
// https://www.w3.org/TR/activitystreams-vocabulary
|
||||
const (
|
||||
|
|
@ -102,9 +105,12 @@ const (
|
|||
|
||||
/* GtS stuff */
|
||||
|
||||
ObjectLikeApproval = "LikeApproval"
|
||||
ObjectReplyApproval = "ReplyApproval"
|
||||
ObjectAnnounceApproval = "AnnounceApproval"
|
||||
ActivityLikeRequest = "LikeRequest"
|
||||
ActivityReplyRequest = "ReplyRequest"
|
||||
ActivityAnnounceRequest = "AnnounceRequest"
|
||||
ObjectLikeAuthorization = "LikeAuthorization"
|
||||
ObjectReplyAuthorization = "ReplyAuthorization"
|
||||
ObjectAnnounceAuthorization = "AnnounceAuthorization"
|
||||
|
||||
/* Funkwhale stuff */
|
||||
|
||||
|
|
@ -138,7 +144,10 @@ func isActivity(typeName string) bool {
|
|||
ActivityAnnounce,
|
||||
ActivityBlock,
|
||||
ActivityFlag,
|
||||
ActivityDislike:
|
||||
ActivityDislike,
|
||||
ActivityLikeRequest,
|
||||
ActivityReplyRequest,
|
||||
ActivityAnnounceRequest:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can like.
|
||||
canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canLikeAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canLikeAlwaysProp.AppendIRI(ap.PublicIRI())
|
||||
canLike.SetGoToSocialAlways(canLikeAlwaysProp)
|
||||
|
||||
// Empty approvalRequired.
|
||||
|
|
@ -127,7 +127,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can reply.
|
||||
canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canReplyAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canReplyAlwaysProp.AppendIRI(ap.PublicIRI())
|
||||
canReply.SetGoToSocialAlways(canReplyAlwaysProp)
|
||||
|
||||
// Set empty approvalRequired.
|
||||
|
|
@ -150,7 +150,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Public requires approval to announce.
|
||||
canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicURI())
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicIRI())
|
||||
canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp)
|
||||
|
||||
// Set canAnnounce on the policy.
|
||||
|
|
@ -265,7 +265,7 @@ func addressable1() ap.Addressable {
|
|||
note := streams.NewActivityStreamsNote()
|
||||
|
||||
toProp := streams.NewActivityStreamsToProperty()
|
||||
toProp.AppendIRI(ap.PublicURI())
|
||||
toProp.AppendIRI(ap.PublicIRI())
|
||||
|
||||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ func addressable2() ap.Addressable {
|
|||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
ccProp := streams.NewActivityStreamsCcProperty()
|
||||
ccProp.AppendIRI(ap.PublicURI())
|
||||
ccProp.AppendIRI(ap.PublicIRI())
|
||||
|
||||
note.SetActivityStreamsCc(ccProp)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import (
|
|||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// ExtractObjects will extract object vocab.Types from given implementing interface.
|
||||
// ExtractObjects will extract object TypeOrIRIs from given implementing interface.
|
||||
func ExtractObjects(with WithObject) []TypeOrIRI {
|
||||
// Extract the attached object (if any).
|
||||
objProp := with.GetActivityStreamsObject()
|
||||
|
|
@ -58,6 +58,28 @@ func ExtractObjects(with WithObject) []TypeOrIRI {
|
|||
return objs
|
||||
}
|
||||
|
||||
// ExtractInstrument will extract instrument TypeOrIRIs from given implementing interface.
|
||||
func ExtractInstruments(with WithInstrument) []TypeOrIRI {
|
||||
// Extract the attached instrument (if any).
|
||||
instrProp := with.GetActivityStreamsInstrument()
|
||||
if instrProp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check for invalid len.
|
||||
if instrProp.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Accumulate all of the instruments into a slice.
|
||||
instrs := make([]TypeOrIRI, instrProp.Len())
|
||||
for i := range instrProp.Len() {
|
||||
instrs[i] = instrProp.At(i)
|
||||
}
|
||||
|
||||
return instrs
|
||||
}
|
||||
|
||||
// ExtractActivityData will extract the usable data type (e.g. Note, Question, etc) and corresponding JSON, from activity.
|
||||
func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeOrIRI, []any, bool) {
|
||||
switch typeName := activity.GetTypeName(); {
|
||||
|
|
@ -1222,14 +1244,14 @@ func ExtractInteractionPolicy(
|
|||
statusable Statusable,
|
||||
owner *gtsmodel.Account,
|
||||
) *gtsmodel.InteractionPolicy {
|
||||
ipa, ok := statusable.(InteractionPolicyAware)
|
||||
wip, ok := statusable.(WithInteractionPolicy)
|
||||
if !ok {
|
||||
// Not a type with interaction
|
||||
// policy properties settable.
|
||||
return nil
|
||||
}
|
||||
|
||||
policyProp := ipa.GetGoToSocialInteractionPolicy()
|
||||
policyProp := wip.GetGoToSocialInteractionPolicy()
|
||||
if policyProp == nil || policyProp.Len() != 1 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,13 +143,13 @@ func ToAcceptable(t vocab.Type) (Acceptable, bool) {
|
|||
return acceptable, true
|
||||
}
|
||||
|
||||
// IsApprovable returns whether AS vocab type name
|
||||
// is something that can be cast to Approvable.
|
||||
func IsApprovable(typeName string) bool {
|
||||
// IsAuthorizationable returns whether AS vocab type name
|
||||
// is something that can be cast to Authorizationable.
|
||||
func IsAuthorizationable(typeName string) bool {
|
||||
switch typeName {
|
||||
case ObjectLikeApproval,
|
||||
ObjectReplyApproval,
|
||||
ObjectAnnounceApproval:
|
||||
case ObjectLikeAuthorization,
|
||||
ObjectReplyAuthorization,
|
||||
ObjectAnnounceAuthorization:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
@ -157,12 +157,12 @@ func IsApprovable(typeName string) bool {
|
|||
}
|
||||
|
||||
// ToAcceptable safely tries to cast vocab.Type as Approvable.
|
||||
func ToApprovable(t vocab.Type) (Approvable, bool) {
|
||||
approvable, ok := t.(Approvable)
|
||||
if !ok || !IsApprovable(t.GetTypeName()) {
|
||||
func ToAuthorizationable(t vocab.Type) (Authorizationable, bool) {
|
||||
authable, ok := t.(Authorizationable)
|
||||
if !ok || !IsAuthorizationable(t.GetTypeName()) {
|
||||
return nil, false
|
||||
}
|
||||
return approvable, true
|
||||
return authable, true
|
||||
}
|
||||
|
||||
// IsAttachmentable returns whether AS vocab type name
|
||||
|
|
@ -188,6 +188,36 @@ func ToAttachmentable(t vocab.Type) (Attachmentable, bool) {
|
|||
return attachmentable, true
|
||||
}
|
||||
|
||||
// IsAnnounceable returns whether AS vocab type name
|
||||
// is something that can be cast to vocab.ActivityStreamsAnnounce.
|
||||
func IsAnnounceable(typeName string) bool {
|
||||
return typeName == ActivityAnnounce
|
||||
}
|
||||
|
||||
// ToAnnounceable safely tries to cast vocab.Type as vocab.ActivityStreamsAnnounce.
|
||||
func ToAnnounceable(t vocab.Type) (vocab.ActivityStreamsAnnounce, bool) {
|
||||
announceable, ok := t.(vocab.ActivityStreamsAnnounce)
|
||||
if !ok || t.GetTypeName() != ActivityAnnounce {
|
||||
return nil, false
|
||||
}
|
||||
return announceable, true
|
||||
}
|
||||
|
||||
// IsLikeable returns whether AS vocab type name
|
||||
// is something that can be cast to vocab.ActivityStreamsLike.
|
||||
func IsLikeable(typeName string) bool {
|
||||
return typeName == ActivityLike
|
||||
}
|
||||
|
||||
// ToAnnouncToLikeableeable safely tries to cast vocab.Type as vocab.ActivityStreamsLike.
|
||||
func ToLikeable(t vocab.Type) (vocab.ActivityStreamsLike, bool) {
|
||||
likeable, ok := t.(vocab.ActivityStreamsLike)
|
||||
if !ok || t.GetTypeName() != ActivityLike {
|
||||
return nil, false
|
||||
}
|
||||
return likeable, true
|
||||
}
|
||||
|
||||
// Activityable represents the minimum activitypub interface for representing an 'activity'.
|
||||
// (see: IsActivityable() for types implementing this, though you MUST make sure to check
|
||||
// the typeName as this bare interface may be implementable by non-Activityable types).
|
||||
|
|
@ -258,11 +288,6 @@ type Statusable interface {
|
|||
WithReplies
|
||||
}
|
||||
|
||||
type InteractionPolicyAware interface {
|
||||
WithInteractionPolicy
|
||||
WithApprovedBy
|
||||
}
|
||||
|
||||
// Pollable represents the minimum activitypub interface for representing a 'poll' (it's a subset of a status).
|
||||
// (see: IsPollable() for types implementing this, though you MUST make sure to check
|
||||
// the typeName as this bare interface may be implementable by non-Pollable types).
|
||||
|
|
@ -299,14 +324,14 @@ type Acceptable interface {
|
|||
WithResult
|
||||
}
|
||||
|
||||
// Approvable represents the minimum activitypub interface
|
||||
// for a LikeApproval, ReplyApproval, or AnnounceApproval.
|
||||
type Approvable interface {
|
||||
// Authorizationable represents the minimum interface for a
|
||||
// LikeAuthorization, ReplyAuthorization, AnnounceAuthorization.
|
||||
type Authorizationable interface {
|
||||
vocab.Type
|
||||
|
||||
WithAttributedTo
|
||||
WithObject
|
||||
WithTarget
|
||||
WithInteractingObject
|
||||
WithInteractionTarget
|
||||
}
|
||||
|
||||
// Attachmentable represents the minimum activitypub interface for representing a 'mediaAttachment'. (see: IsAttachmentable).
|
||||
|
|
@ -392,6 +417,16 @@ type ReplyToable interface {
|
|||
WithInReplyTo
|
||||
}
|
||||
|
||||
// InteractionRequestable represents the minimum interface for an interaction request
|
||||
// activity, eg., LikeRequest, ReplyRequest, AnnounceRequest, QuoteRequest, etc..
|
||||
type InteractionRequestable interface {
|
||||
vocab.Type
|
||||
|
||||
WithActor
|
||||
WithObject
|
||||
WithInstrument
|
||||
}
|
||||
|
||||
// CollectionIterator represents the minimum interface for interacting with a
|
||||
// wrapped Collection or OrderedCollection in order to access next / prev items.
|
||||
type CollectionIterator interface {
|
||||
|
|
@ -683,6 +718,12 @@ type WithObject interface {
|
|||
SetActivityStreamsObject(vocab.ActivityStreamsObjectProperty)
|
||||
}
|
||||
|
||||
// WithInstrument represents an activity with ActivityStreamsInstrumentProperty
|
||||
type WithInstrument interface {
|
||||
GetActivityStreamsInstrument() vocab.ActivityStreamsInstrumentProperty
|
||||
SetActivityStreamsInstrument(vocab.ActivityStreamsInstrumentProperty)
|
||||
}
|
||||
|
||||
// WithTarget represents an activity with ActivityStreamsTargetProperty
|
||||
type WithTarget interface {
|
||||
GetActivityStreamsTarget() vocab.ActivityStreamsTargetProperty
|
||||
|
|
@ -775,14 +816,44 @@ type WithPolicyRules interface {
|
|||
GetGoToSocialApprovalRequired() vocab.GoToSocialApprovalRequiredProperty // Deprecated
|
||||
}
|
||||
|
||||
// WithApprovedBy represents a Statusable with the approvedBy property.
|
||||
// WithApprovedBy represents an object with the approvedBy property.
|
||||
type WithApprovedBy interface {
|
||||
GetGoToSocialApprovedBy() vocab.GoToSocialApprovedByProperty
|
||||
SetGoToSocialApprovedBy(vocab.GoToSocialApprovedByProperty)
|
||||
}
|
||||
|
||||
// WithVotersCount represents an activity or object the result property.
|
||||
// WithLikeAuthorization represents a Likeable with the likeAuthorization property.
|
||||
type WithLikeAuthorization interface {
|
||||
GetGoToSocialLikeAuthorization() vocab.GoToSocialLikeAuthorizationProperty
|
||||
SetGoToSocialLikeAuthorization(vocab.GoToSocialLikeAuthorizationProperty)
|
||||
}
|
||||
|
||||
// WithReplyAuthorization represents a statusable with the replyAuthorization property.
|
||||
type WithReplyAuthorization interface {
|
||||
GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty
|
||||
SetGoToSocialReplyAuthorization(vocab.GoToSocialReplyAuthorizationProperty)
|
||||
}
|
||||
|
||||
// WithAnnounceAuthorization represents an Announceable with the announceAuthorization property.
|
||||
type WithAnnounceAuthorization interface {
|
||||
GetGoToSocialAnnounceAuthorization() vocab.GoToSocialAnnounceAuthorizationProperty
|
||||
SetGoToSocialAnnounceAuthorization(vocab.GoToSocialAnnounceAuthorizationProperty)
|
||||
}
|
||||
|
||||
// WithResult represents an activity or object with the result property.
|
||||
type WithResult interface {
|
||||
GetActivityStreamsResult() vocab.ActivityStreamsResultProperty
|
||||
SetActivityStreamsResult(vocab.ActivityStreamsResultProperty)
|
||||
}
|
||||
|
||||
// WithInteractingObject represents an activity or object with the InteractingObject property.
|
||||
type WithInteractingObject interface {
|
||||
GetGoToSocialInteractingObject() vocab.GoToSocialInteractingObjectProperty
|
||||
SetGoToSocialInteractingObject(vocab.GoToSocialInteractingObjectProperty)
|
||||
}
|
||||
|
||||
// WithInteractionTarget represents an activity or object with the InteractionTarget property.
|
||||
type WithInteractionTarget interface {
|
||||
GetGoToSocialInteractionTarget() vocab.GoToSocialInteractionTargetProperty
|
||||
SetGoToSocialInteractionTarget(vocab.GoToSocialInteractionTargetProperty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,6 +226,36 @@ func AppendObjectIRIs(with WithObject, object ...*url.URL) {
|
|||
}, object...)
|
||||
}
|
||||
|
||||
// AppendInstrumentIRIs appends the given IRIs to the Instrument property of 'with'.
|
||||
func AppendInstrumentIRIs(with WithInstrument, instrument ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsInstrumentPropertyIterator] {
|
||||
instrumentProp := with.GetActivityStreamsInstrument()
|
||||
if instrumentProp == nil {
|
||||
instrumentProp = streams.NewActivityStreamsInstrumentProperty()
|
||||
with.SetActivityStreamsInstrument(instrumentProp)
|
||||
}
|
||||
return instrumentProp
|
||||
}, instrument...)
|
||||
}
|
||||
|
||||
// GetResultIRIs returns the IRIs contained in the `result` property of 'with'.
|
||||
func GetResultIRIs(with WithResult) []*url.URL {
|
||||
resultProp := with.GetActivityStreamsResult()
|
||||
return extractIRIs(resultProp)
|
||||
}
|
||||
|
||||
// AppendResultIRIs appends the given IRIs to the Result property of 'with'.
|
||||
func AppendResultIRIs(with WithResult, result ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.ActivityStreamsResultPropertyIterator] {
|
||||
resultProp := with.GetActivityStreamsResult()
|
||||
if resultProp == nil {
|
||||
resultProp = streams.NewActivityStreamsResultProperty()
|
||||
with.SetActivityStreamsResult(resultProp)
|
||||
}
|
||||
return resultProp
|
||||
}, result...)
|
||||
}
|
||||
|
||||
// GetTargetIRIs returns the IRIs contained in the Target property of 'with'.
|
||||
func GetTargetIRIs(with WithTarget) []*url.URL {
|
||||
targetProp := with.GetActivityStreamsTarget()
|
||||
|
|
@ -262,6 +292,42 @@ func AppendAttributedTo(with WithAttributedTo, attribTo ...*url.URL) {
|
|||
}, attribTo...)
|
||||
}
|
||||
|
||||
// GetInteractingObject returns IRIs contained in the interactingObject property of 'with'.
|
||||
func GetInteractingObject(with WithInteractingObject) []*url.URL {
|
||||
intObjProp := with.GetGoToSocialInteractingObject()
|
||||
return getIRIs(intObjProp)
|
||||
}
|
||||
|
||||
// AppendInteractingObject appends the given IRIs to the interactingObject property of 'with'.
|
||||
func AppendInteractingObject(with WithInteractingObject, interactingObject ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.GoToSocialInteractingObjectPropertyIterator] {
|
||||
intObjProp := with.GetGoToSocialInteractingObject()
|
||||
if intObjProp == nil {
|
||||
intObjProp = streams.NewGoToSocialInteractingObjectProperty()
|
||||
with.SetGoToSocialInteractingObject(intObjProp)
|
||||
}
|
||||
return intObjProp
|
||||
}, interactingObject...)
|
||||
}
|
||||
|
||||
// GetInteractionTarget returns IRIs contained in the interactionTarget property of 'with'.
|
||||
func GetInteractionTarget(with WithInteractionTarget) []*url.URL {
|
||||
intTargetProp := with.GetGoToSocialInteractionTarget()
|
||||
return getIRIs(intTargetProp)
|
||||
}
|
||||
|
||||
// AppendInteractionTarget appends the given IRIs to the interactionTarget property of 'with'.
|
||||
func AppendInteractionTarget(with WithInteractionTarget, interactionTarget ...*url.URL) {
|
||||
appendIRIs(func() Property[vocab.GoToSocialInteractionTargetPropertyIterator] {
|
||||
intTargetProp := with.GetGoToSocialInteractionTarget()
|
||||
if intTargetProp == nil {
|
||||
intTargetProp = streams.NewGoToSocialInteractionTargetProperty()
|
||||
with.SetGoToSocialInteractionTarget(intTargetProp)
|
||||
}
|
||||
return intTargetProp
|
||||
}, interactionTarget...)
|
||||
}
|
||||
|
||||
// GetInReplyTo returns the IRIs contained in the InReplyTo property of 'with'.
|
||||
func GetInReplyTo(with WithInReplyTo) []*url.URL {
|
||||
replyProp := with.GetActivityStreamsInReplyTo()
|
||||
|
|
@ -607,11 +673,11 @@ func SetHidesCcPublicFromUnauthedWeb(with WithHidesCcPublicFromUnauthedWeb, hide
|
|||
// GetApprovedBy returns the URL contained in
|
||||
// the ApprovedBy property of 'with', if set.
|
||||
func GetApprovedBy(with WithApprovedBy) *url.URL {
|
||||
mafProp := with.GetGoToSocialApprovedBy()
|
||||
if mafProp == nil || !mafProp.IsIRI() {
|
||||
abProp := with.GetGoToSocialApprovedBy()
|
||||
if abProp == nil || !abProp.IsIRI() {
|
||||
return nil
|
||||
}
|
||||
return mafProp.Get()
|
||||
return abProp.Get()
|
||||
}
|
||||
|
||||
// SetApprovedBy sets the given url
|
||||
|
|
@ -625,6 +691,69 @@ func SetApprovedBy(with WithApprovedBy, approvedBy *url.URL) {
|
|||
abProp.Set(approvedBy)
|
||||
}
|
||||
|
||||
// GetLikeAuthorization returns the URL contained in
|
||||
// the likeAuthorization property of 'with', if set.
|
||||
func GetLikeAuthorization(with WithLikeAuthorization) *url.URL {
|
||||
laProp := with.GetGoToSocialLikeAuthorization()
|
||||
if laProp == nil || !laProp.IsIRI() {
|
||||
return nil
|
||||
}
|
||||
return laProp.Get()
|
||||
}
|
||||
|
||||
// SetLikeAuthorization sets the given url on
|
||||
// the 'likeAuthorization' property of 'with'.
|
||||
func SetLikeAuthorization(with WithLikeAuthorization, likeAuthorization *url.URL) {
|
||||
laProp := with.GetGoToSocialLikeAuthorization()
|
||||
if laProp == nil {
|
||||
laProp = streams.NewGoToSocialLikeAuthorizationProperty()
|
||||
with.SetGoToSocialLikeAuthorization(laProp)
|
||||
}
|
||||
laProp.Set(likeAuthorization)
|
||||
}
|
||||
|
||||
// GetReplyAuthorization returns the URL contained in
|
||||
// the replyAuthorization property of 'with', if set.
|
||||
func GetReplyAuthorization(with WithReplyAuthorization) *url.URL {
|
||||
raProp := with.GetGoToSocialReplyAuthorization()
|
||||
if raProp == nil || !raProp.IsIRI() {
|
||||
return nil
|
||||
}
|
||||
return raProp.Get()
|
||||
}
|
||||
|
||||
// SetReplyAuthorization sets the given url on
|
||||
// the 'replyAuthorization' property of 'with'.
|
||||
func SetReplyAuthorization(with WithReplyAuthorization, replyAuthorization *url.URL) {
|
||||
raProp := with.GetGoToSocialReplyAuthorization()
|
||||
if raProp == nil {
|
||||
raProp = streams.NewGoToSocialReplyAuthorizationProperty()
|
||||
with.SetGoToSocialReplyAuthorization(raProp)
|
||||
}
|
||||
raProp.Set(replyAuthorization)
|
||||
}
|
||||
|
||||
// GetAnnounceAuthorization returns the URL contained in
|
||||
// the announceAuthorization property of 'with', if set.
|
||||
func GetAnnounceAuthorization(with WithAnnounceAuthorization) *url.URL {
|
||||
aaProp := with.GetGoToSocialAnnounceAuthorization()
|
||||
if aaProp == nil || !aaProp.IsIRI() {
|
||||
return nil
|
||||
}
|
||||
return aaProp.Get()
|
||||
}
|
||||
|
||||
// SetAnnounceAuthorization sets the given url on
|
||||
// the 'announceAuthorization' property of 'with'.
|
||||
func SetAnnounceAuthorization(with WithAnnounceAuthorization, announceAuthorization *url.URL) {
|
||||
aaProp := with.GetGoToSocialAnnounceAuthorization()
|
||||
if aaProp == nil {
|
||||
aaProp = streams.NewGoToSocialAnnounceAuthorizationProperty()
|
||||
with.SetGoToSocialAnnounceAuthorization(aaProp)
|
||||
}
|
||||
aaProp.Set(announceAuthorization)
|
||||
}
|
||||
|
||||
// GetMediaType returns the string contained in
|
||||
// the MediaType property of 'with', if set.
|
||||
func GetMediaType(with WithMediaType) string {
|
||||
|
|
@ -689,6 +818,50 @@ func SetBlurhash(with WithBlurhash, mediaType string) {
|
|||
bProp.Set(mediaType)
|
||||
}
|
||||
|
||||
// AppendSensitive appends the given sensitive
|
||||
// boolean to the `sensitive` property of 'with'.
|
||||
func AppendSensitive(with WithSensitive, sensitive bool) {
|
||||
sProp := with.GetActivityStreamsSensitive()
|
||||
if sProp == nil {
|
||||
sProp = streams.NewActivityStreamsSensitiveProperty()
|
||||
with.SetActivityStreamsSensitive(sProp)
|
||||
}
|
||||
sProp.AppendXMLSchemaBoolean(sensitive)
|
||||
}
|
||||
|
||||
// AppendContent appends the given content
|
||||
// string to the `content` property of 'with'.
|
||||
func AppendContent(with WithContent, content string) {
|
||||
cProp := with.GetActivityStreamsContent()
|
||||
if cProp == nil {
|
||||
cProp = streams.NewActivityStreamsContentProperty()
|
||||
with.SetActivityStreamsContent(cProp)
|
||||
}
|
||||
cProp.AppendXMLSchemaString(content)
|
||||
}
|
||||
|
||||
// AppendContentMap appends the given content
|
||||
// language map to the `content` property of 'with'.
|
||||
func AppendContentMap(with WithContent, contentMap map[string]string) {
|
||||
cProp := with.GetActivityStreamsContent()
|
||||
if cProp == nil {
|
||||
cProp = streams.NewActivityStreamsContentProperty()
|
||||
with.SetActivityStreamsContent(cProp)
|
||||
}
|
||||
cProp.AppendRDFLangString(contentMap)
|
||||
}
|
||||
|
||||
// SetReplies sets the given replies collection
|
||||
// to the `replies` property of 'with'.
|
||||
func SetReplies(with WithReplies, replies vocab.ActivityStreamsCollection) {
|
||||
rProp := with.GetActivityStreamsReplies()
|
||||
if rProp == nil {
|
||||
rProp = streams.NewActivityStreamsRepliesProperty()
|
||||
with.SetActivityStreamsReplies(rProp)
|
||||
}
|
||||
rProp.SetActivityStreamsCollection(replies)
|
||||
}
|
||||
|
||||
// extractIRIs extracts just the AP IRIs from an iterable
|
||||
// property that may contain types (with IRIs) or just IRIs.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -153,8 +153,8 @@ func serializeStatusable(t vocab.Type, includeContext bool) (map[string]interfac
|
|||
|
||||
NormalizeOutgoingAttachmentProp(statusable, data)
|
||||
NormalizeOutgoingContentProp(statusable, data)
|
||||
if ipa, ok := statusable.(InteractionPolicyAware); ok {
|
||||
NormalizeOutgoingInteractionPolicyProp(ipa, data)
|
||||
if wip, ok := statusable.(WithInteractionPolicy); ok {
|
||||
NormalizeOutgoingInteractionPolicyProp(wip, data)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
|
|
|
|||
56
internal/api/activitypub/users/authorizationget.go
Normal file
56
internal/api/activitypub/users/authorizationget.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AuthorizationGETHandler serves an accepted interaction request as a
|
||||
// LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization type.
|
||||
func (m *Module) AuthorizationGETHandler(c *gin.Context) {
|
||||
username, errWithCode := apiutil.ParseUsername(c.Param(apiutil.UsernameKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
reqID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
contentType, err := apiutil.NegotiateAccept(c, apiutil.ActivityPubHeaders...)
|
||||
if err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.Fedi().AuthorizationGet(c.Request.Context(), username, reqID)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSONType(c, http.StatusOK, contentType, resp)
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, de
|
|||
|
||||
// Set the To of the delete as public
|
||||
deleteTo := streams.NewActivityStreamsToProperty()
|
||||
deleteTo.AppendIRI(ap.PublicURI())
|
||||
deleteTo.AppendIRI(ap.PublicIRI())
|
||||
delete.SetActivityStreamsTo(deleteTo)
|
||||
|
||||
// set some random-ass ID for the activity
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ const (
|
|||
StatusRepliesPath = StatusPath + "/replies"
|
||||
// AcceptPath is for serving accepts of a status.
|
||||
AcceptPath = BasePath + "/" + uris.AcceptsPath + "/:" + apiutil.IDKey
|
||||
// AuthorizationsPath is for serving authorizations of an interaction.
|
||||
AuthorizationsPath = BasePath + "/" + uris.AuthorizationsPath + "/:" + apiutil.IDKey
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
|
|
@ -80,4 +82,5 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
|||
attachHandler(http.MethodGet, StatusRepliesPath, m.StatusRepliesGETHandler)
|
||||
attachHandler(http.MethodGet, OutboxPath, m.OutboxGETHandler)
|
||||
attachHandler(http.MethodGet, AcceptPath, m.AcceptGETHandler)
|
||||
attachHandler(http.MethodGet, AuthorizationsPath, m.AuthorizationGETHandler)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -730,7 +730,7 @@ func (suite *StatusBoostTestSuite) TestPostBoostImplicitAccept() {
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.NotZero(intReq.AcceptedAt)
|
||||
suite.NotEmpty(intReq.URI)
|
||||
suite.NotEmpty(intReq.InteractionURI)
|
||||
}
|
||||
|
||||
func TestStatusBoostTestSuite(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ func (suite *StatusFaveTestSuite) TestPostFaveImplicitAccept() {
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.NotZero(intReq.AcceptedAt)
|
||||
suite.NotEmpty(intReq.URI)
|
||||
suite.NotEmpty(intReq.InteractionURI)
|
||||
|
||||
// Check visibility of status to public after posting fave.
|
||||
visible, err = visFilter.StatusVisible(ctx, nil, dbStatus)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,4 @@ type InteractionRequest struct {
|
|||
AcceptedAt string `json:"accepted_at,omitempty"`
|
||||
// The timestamp that the interaction request was rejected (ISO 8601 Datetime). Field omitted if request not rejected (yet).
|
||||
RejectedAt string `json:"rejected_at,omitempty"`
|
||||
// URI of the Accept or Reject. Only set if accepted_at or rejected_at is set, else omitted.
|
||||
URI string `json:"uri,omitempty"`
|
||||
}
|
||||
|
|
|
|||
6
internal/cache/db.go
vendored
6
internal/cache/db.go
vendored
|
|
@ -944,7 +944,7 @@ func (c *Caches) initInteractionRequest() {
|
|||
// Don't include ptr fields that
|
||||
// will be populated separately.
|
||||
// See internal/db/bundb/interaction.go.
|
||||
i2.Status = nil
|
||||
i2.TargetStatus = nil
|
||||
i2.TargetAccount = nil
|
||||
i2.InteractingAccount = nil
|
||||
i2.Like = nil
|
||||
|
|
@ -958,7 +958,9 @@ func (c *Caches) initInteractionRequest() {
|
|||
Indices: []structr.IndexConfig{
|
||||
{Fields: "ID"},
|
||||
{Fields: "InteractionURI"},
|
||||
{Fields: "URI"},
|
||||
{Fields: "InteractionRequestURI"},
|
||||
{Fields: "ResponseURI"},
|
||||
{Fields: "AuthorizationURI"},
|
||||
},
|
||||
MaxSize: cap,
|
||||
IgnoreErr: ignoreErrors,
|
||||
|
|
|
|||
19
internal/cache/size.go
vendored
19
internal/cache/size.go
vendored
|
|
@ -418,15 +418,16 @@ func sizeofInstance() uintptr {
|
|||
|
||||
func sizeofInteractionRequest() uintptr {
|
||||
return uintptr(size.Of(>smodel.InteractionRequest{
|
||||
ID: exampleID,
|
||||
CreatedAt: exampleTime,
|
||||
StatusID: exampleID,
|
||||
TargetAccountID: exampleID,
|
||||
InteractingAccountID: exampleID,
|
||||
InteractionURI: exampleURI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
URI: exampleURI,
|
||||
AcceptedAt: exampleTime,
|
||||
ID: exampleID,
|
||||
TargetStatusID: exampleID,
|
||||
TargetAccountID: exampleID,
|
||||
InteractingAccountID: exampleID,
|
||||
InteractionRequestURI: exampleURI,
|
||||
InteractionURI: exampleURI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
AcceptedAt: exampleTime,
|
||||
ResponseURI: exampleURI,
|
||||
AuthorizationURI: exampleURI,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,12 +106,7 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
|||
// with this username, create one now.
|
||||
if account == nil {
|
||||
uris := uris.GenerateURIsForAccount(newSignup.Username)
|
||||
|
||||
accountID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error creating new account id: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
accountID := id.NewRandomULID()
|
||||
|
||||
privKey, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
|
||||
if err != nil {
|
||||
|
|
@ -174,12 +169,9 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
|||
return user, nil
|
||||
}
|
||||
|
||||
// Had no user for this account, time to create one!
|
||||
newUserID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error creating new user id: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
// Had no user for this
|
||||
// account, time to create one!
|
||||
newUserID := id.NewRandomULID()
|
||||
|
||||
encryptedPassword, err := bcrypt.GenerateFromPassword(
|
||||
[]byte(newSignup.Password),
|
||||
|
|
@ -273,14 +265,9 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
aID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAccountURIs := uris.GenerateURIsForAccount(username)
|
||||
acct := >smodel.Account{
|
||||
ID: aID,
|
||||
ID: id.NewRandomULID(),
|
||||
Username: username,
|
||||
DisplayName: username,
|
||||
URL: newAccountURIs.UserURL,
|
||||
|
|
@ -325,13 +312,8 @@ func (a *adminDB) CreateInstanceInstance(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
iID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i := >smodel.Instance{
|
||||
ID: iID,
|
||||
ID: id.NewRandomULID(),
|
||||
Domain: host,
|
||||
Title: host,
|
||||
URI: fmt.Sprintf("%s://%s", protocol, host),
|
||||
|
|
|
|||
|
|
@ -58,31 +58,45 @@ func (i *interactionDB) GetInteractionRequestByID(ctx context.Context, id string
|
|||
)
|
||||
}
|
||||
|
||||
func (i *interactionDB) GetInteractionRequestByInteractionURI(ctx context.Context, uri string) (*gtsmodel.InteractionRequest, error) {
|
||||
func (i *interactionDB) GetInteractionRequestByInteractionURI(ctx context.Context, intURI string) (*gtsmodel.InteractionRequest, error) {
|
||||
return i.getInteractionRequest(
|
||||
ctx,
|
||||
"InteractionURI",
|
||||
func(request *gtsmodel.InteractionRequest) error {
|
||||
return i.
|
||||
newInteractionRequestQ(request).
|
||||
Where("? = ?", bun.Ident("interaction_request.interaction_uri"), uri).
|
||||
Where("? = ?", bun.Ident("interaction_request.interaction_uri"), intURI).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
intURI,
|
||||
)
|
||||
}
|
||||
|
||||
func (i *interactionDB) GetInteractionRequestByURI(ctx context.Context, uri string) (*gtsmodel.InteractionRequest, error) {
|
||||
func (i *interactionDB) GetInteractionRequestByResponseURI(ctx context.Context, respURI string) (*gtsmodel.InteractionRequest, error) {
|
||||
return i.getInteractionRequest(
|
||||
ctx,
|
||||
"URI",
|
||||
"ResponseURI",
|
||||
func(request *gtsmodel.InteractionRequest) error {
|
||||
return i.
|
||||
newInteractionRequestQ(request).
|
||||
Where("? = ?", bun.Ident("interaction_request.uri"), uri).
|
||||
Where("? = ?", bun.Ident("interaction_request.response_uri"), respURI).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
respURI,
|
||||
)
|
||||
}
|
||||
|
||||
func (i *interactionDB) GetInteractionRequestByAuthorizationURI(ctx context.Context, authURI string) (*gtsmodel.InteractionRequest, error) {
|
||||
return i.getInteractionRequest(
|
||||
ctx,
|
||||
"AuthorizationURI",
|
||||
func(request *gtsmodel.InteractionRequest) error {
|
||||
return i.
|
||||
newInteractionRequestQ(request).
|
||||
Where("? = ?", bun.Ident("interaction_request.authorization_uri"), authURI).
|
||||
Scan(ctx)
|
||||
},
|
||||
authURI,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -173,11 +187,11 @@ func (i *interactionDB) PopulateInteractionRequest(ctx context.Context, req *gts
|
|||
errs = gtserror.NewMultiError(4)
|
||||
)
|
||||
|
||||
if req.Status == nil {
|
||||
if req.TargetStatus == nil {
|
||||
// Target status is not set, fetch from the database.
|
||||
req.Status, err = i.state.DB.GetStatusByID(
|
||||
req.TargetStatus, err = i.state.DB.GetStatusByID(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
req.StatusID,
|
||||
req.TargetStatusID,
|
||||
)
|
||||
if err != nil {
|
||||
errs.Appendf("error populating interactionRequest target: %w", err)
|
||||
|
|
|
|||
|
|
@ -57,9 +57,8 @@ func (suite *InteractionTestSuite) markInteractionsPending(
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Put an interaction request
|
||||
// in the DB for this reply.
|
||||
req := typeutils.StatusToInteractionRequest(reply)
|
||||
// Put an impolite interaction request in the DB for this reply.
|
||||
req := typeutils.StatusToImpoliteInteractionRequest(reply)
|
||||
if err := suite.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
|
@ -84,9 +83,8 @@ func (suite *InteractionTestSuite) markInteractionsPending(
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Put an interaction request
|
||||
// in the DB for this boost.
|
||||
req := typeutils.StatusToInteractionRequest(boost)
|
||||
// Put an impolite interaction request in the DB for this boost.
|
||||
req := typeutils.StatusToImpoliteInteractionRequest(boost)
|
||||
if err := suite.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
|
@ -111,9 +109,8 @@ func (suite *InteractionTestSuite) markInteractionsPending(
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Put an interaction request
|
||||
// in the DB for this fave.
|
||||
req := typeutils.StatusFaveToInteractionRequest(fave)
|
||||
// Put an impolite interaction request in the DB for this fave.
|
||||
req := typeutils.StatusFaveToImpoliteInteractionRequest(fave)
|
||||
if err := suite.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
|
@ -229,8 +226,8 @@ func (suite *InteractionTestSuite) TestInteractionRejected() {
|
|||
|
||||
// Update the interaction request to mark it rejected.
|
||||
req.RejectedAt = time.Now()
|
||||
req.URI = "https://some.reject.uri"
|
||||
if err := suite.state.DB.UpdateInteractionRequest(ctx, req, "uri", "rejected_at"); err != nil {
|
||||
req.ResponseURI = "https://some.reject.uri"
|
||||
if err := suite.state.DB.UpdateInteractionRequest(ctx, req, "response_uri", "rejected_at"); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,328 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/config"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/dialect"
|
||||
|
||||
new_gtsmodel "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/new"
|
||||
old_gtsmodel "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/old"
|
||||
)
|
||||
|
||||
func init() {
|
||||
up := func(ctx context.Context, db *bun.DB) error {
|
||||
const tmpTableName = "new_interaction_requests"
|
||||
const tableName = "interaction_requests"
|
||||
var host = config.GetHost()
|
||||
var accountDomain = config.GetAccountDomain()
|
||||
|
||||
// Count number of interaction
|
||||
// requests we need to update.
|
||||
total, err := db.NewSelect().
|
||||
Table(tableName).
|
||||
Count(ctx)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error geting interaction requests table count: %w", err)
|
||||
}
|
||||
|
||||
// Create new interaction_requests table and convert all existing into it.
|
||||
if err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
|
||||
log.Info(ctx, "creating new interaction_requests table")
|
||||
if _, err := tx.NewCreateTable().
|
||||
ModelTableExpr(tmpTableName).
|
||||
Model((*new_gtsmodel.InteractionRequest)(nil)).
|
||||
Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error creating new interaction requests table: %w", err)
|
||||
}
|
||||
|
||||
// Conversion batch size.
|
||||
const batchsz = 1000
|
||||
|
||||
var maxID string
|
||||
var count int
|
||||
|
||||
// Start at largest
|
||||
// possible ULID value.
|
||||
maxID = id.Highest
|
||||
|
||||
// Preallocate interaction request slices to maximum possible size.
|
||||
oldRequests := make([]*old_gtsmodel.InteractionRequest, 0, batchsz)
|
||||
newRequests := make([]*new_gtsmodel.InteractionRequest, 0, batchsz)
|
||||
|
||||
log.Info(ctx, "migrating interaction requests to new table, this may take some time!")
|
||||
outer:
|
||||
for {
|
||||
// Reset slices slices.
|
||||
clear(oldRequests)
|
||||
clear(newRequests)
|
||||
oldRequests = oldRequests[:0]
|
||||
newRequests = newRequests[:0]
|
||||
|
||||
// Select next batch of
|
||||
// interaction requests.
|
||||
if err := tx.NewSelect().
|
||||
Model(&oldRequests).
|
||||
Where("? < ?", bun.Ident("id"), maxID).
|
||||
OrderExpr("? DESC", bun.Ident("id")).
|
||||
Limit(batchsz).
|
||||
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return gtserror.Newf("error selecting interaction requests: %w", err)
|
||||
}
|
||||
|
||||
// Reached end of requests.
|
||||
if len(oldRequests) == 0 {
|
||||
break outer
|
||||
}
|
||||
|
||||
// Set next maxID value from old requests.
|
||||
maxID = oldRequests[len(oldRequests)-1].ID
|
||||
|
||||
inner:
|
||||
// Convert old request models to new.
|
||||
for _, oldRequest := range oldRequests {
|
||||
newRequest := &new_gtsmodel.InteractionRequest{
|
||||
ID: oldRequest.ID,
|
||||
TargetStatusID: oldRequest.StatusID,
|
||||
TargetAccountID: oldRequest.TargetAccountID,
|
||||
InteractingAccountID: oldRequest.InteractingAccountID,
|
||||
InteractionURI: oldRequest.InteractionURI,
|
||||
InteractionType: int16(oldRequest.InteractionType), // #nosec G115
|
||||
Polite: util.Ptr(false), // old requests were always impolite
|
||||
AcceptedAt: oldRequest.AcceptedAt,
|
||||
RejectedAt: oldRequest.RejectedAt,
|
||||
ResponseURI: oldRequest.URI,
|
||||
}
|
||||
|
||||
// Append new request to slice,
|
||||
// though we continue operating on
|
||||
// its ptr in the rest of this loop.
|
||||
newRequests = append(newRequests,
|
||||
newRequest)
|
||||
|
||||
// Re-use the original interaction URI to create
|
||||
// a mock interaction request URI on the new model.
|
||||
switch oldRequest.InteractionType {
|
||||
case old_gtsmodel.InteractionLike:
|
||||
newRequest.InteractionRequestURI = oldRequest.InteractionURI + new_gtsmodel.LikeRequestSuffix
|
||||
case old_gtsmodel.InteractionReply:
|
||||
newRequest.InteractionRequestURI = oldRequest.InteractionURI + new_gtsmodel.ReplyRequestSuffix
|
||||
case old_gtsmodel.InteractionAnnounce:
|
||||
newRequest.InteractionRequestURI = oldRequest.InteractionURI + new_gtsmodel.AnnounceRequestSuffix
|
||||
}
|
||||
|
||||
// If the request was accepted by us, then generate an authorization
|
||||
// URI for it, in order to be able to serve an Authorization if necessary.
|
||||
if oldRequest.AcceptedAt.IsZero() || oldRequest.URI == "" {
|
||||
|
||||
// Wasn't accepted,
|
||||
// nothing else to do.
|
||||
continue inner
|
||||
}
|
||||
|
||||
// Parse URI details of accept URI string.
|
||||
acceptURI, err := url.Parse(oldRequest.URI)
|
||||
if err != nil {
|
||||
log.Warnf(ctx, "could not parse oldRequest.URI for interaction request %s,"+
|
||||
" skipping forward-compat hack (don't worry, this is not a big deal): %v",
|
||||
oldRequest.ID, err)
|
||||
continue inner
|
||||
}
|
||||
|
||||
// Check whether accept URI originated from this instance.
|
||||
if !(acceptURI.Host == host || acceptURI.Host == accountDomain) {
|
||||
|
||||
// Not an accept from
|
||||
// us, leave it alone.
|
||||
continue inner
|
||||
}
|
||||
|
||||
// Reuse the Accept URI to create an Authorization URI.
|
||||
// Creates `https://example.org/users/aaa/authorizations/[ID]`
|
||||
// from `https://example.org/users/aaa/accepts/[ID]`.
|
||||
authorizationURI := strings.ReplaceAll(
|
||||
oldRequest.URI,
|
||||
"/accepts/"+oldRequest.ID,
|
||||
"/authorizations/"+oldRequest.ID,
|
||||
)
|
||||
newRequest.AuthorizationURI = authorizationURI
|
||||
|
||||
var updateTableName string
|
||||
|
||||
// Determine which table will have corresponding approved_by_uri.
|
||||
if oldRequest.InteractionType == old_gtsmodel.InteractionLike {
|
||||
updateTableName = "status_faves"
|
||||
} else {
|
||||
updateTableName = "statuses"
|
||||
}
|
||||
|
||||
// Update the corresponding interaction
|
||||
// with generated authorization URI.
|
||||
if _, err := tx.NewUpdate().
|
||||
Table(updateTableName).
|
||||
Set("? = ?", bun.Ident("approved_by_uri"), authorizationURI).
|
||||
Where("? = ?", bun.Ident("uri"), oldRequest.InteractionURI).
|
||||
Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error updating approved_by_uri: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert converted interaction
|
||||
// request models to new table.
|
||||
if _, err := tx.
|
||||
NewInsert().
|
||||
Model(&newRequests).
|
||||
Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error inserting interaction requests: %w", err)
|
||||
}
|
||||
|
||||
// Increment insert count.
|
||||
count += len(newRequests)
|
||||
|
||||
log.Infof(ctx, "[%d of %d] converting interaction requests", count, total)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that the above transaction
|
||||
// has gone ahead without issues.
|
||||
//
|
||||
// Also placing this here might make
|
||||
// breaking this into piecemeal steps
|
||||
// easier if turns out necessary.
|
||||
newTotal, err := db.NewSelect().
|
||||
Table(tmpTableName).
|
||||
Count(ctx)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error geting new interaction requests table count: %w", err)
|
||||
} else if total != newTotal {
|
||||
return gtserror.Newf("new interaction requests table contains unexpected count %d, want %d", newTotal, total)
|
||||
}
|
||||
|
||||
// Attempt to merge any sqlite write-ahead-log.
|
||||
if err := doWALCheckpoint(ctx, db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Drop the old interaction requests table and rename new one to replace it.
|
||||
if err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
|
||||
log.Info(ctx, "dropping old interaction_requests table")
|
||||
if _, err := tx.NewDropTable().
|
||||
Table(tableName).
|
||||
Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error dropping old interaction requests table: %w", err)
|
||||
}
|
||||
|
||||
log.Info(ctx, "renaming new interaction_requests table to old")
|
||||
if _, err := tx.NewRaw("ALTER TABLE ? RENAME TO ?",
|
||||
bun.Ident(tmpTableName),
|
||||
bun.Ident(tableName),
|
||||
).Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error renaming interaction requests table: %w", err)
|
||||
}
|
||||
|
||||
// Create necessary indices on the new table.
|
||||
for index, columns := range map[string][]string{
|
||||
"interaction_requests_target_status_id_idx": {"target_status_id"},
|
||||
"interaction_requests_interacting_account_id_idx": {"interacting_account_id"},
|
||||
"interaction_requests_target_account_id_idx": {"target_account_id"},
|
||||
"interaction_requests_accepted_at_idx": {"accepted_at"},
|
||||
"interaction_requests_rejected_at_idx": {"rejected_at"},
|
||||
} {
|
||||
log.Infof(ctx, "recreating %s index", index)
|
||||
if _, err := tx.NewCreateIndex().
|
||||
Table(tableName).
|
||||
Index(index).
|
||||
Column(columns...).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tx.Dialect().Name() == dialect.PG {
|
||||
// Rename postgres uniqueness constraints:
|
||||
// "new_interaction_requests_*" -> "interaction_requests_*"
|
||||
log.Info(ctx, "renaming interaction_requests constraints on new table")
|
||||
for _, spec := range []struct {
|
||||
old string
|
||||
new string
|
||||
}{
|
||||
{
|
||||
old: "new_interaction_requests_pkey",
|
||||
new: "interaction_requests_pkey",
|
||||
},
|
||||
{
|
||||
old: "new_interaction_requests_interaction_request_uri_key",
|
||||
new: "interaction_requests_interaction_request_uri_key",
|
||||
},
|
||||
{
|
||||
old: "new_interaction_requests_interaction_uri_key",
|
||||
new: "interaction_requests_interaction_uri_key",
|
||||
},
|
||||
{
|
||||
old: "new_interaction_requests_response_uri_key",
|
||||
new: "interaction_requests_response_uri_key",
|
||||
},
|
||||
{
|
||||
old: "new_interaction_requests_authorization_uri_key",
|
||||
new: "interaction_requests_authorization_uri_key",
|
||||
},
|
||||
} {
|
||||
if _, err := tx.NewRaw("ALTER TABLE ? RENAME CONSTRAINT ? TO ?",
|
||||
bun.Ident(tableName),
|
||||
bun.Safe(spec.old),
|
||||
bun.Safe(spec.new),
|
||||
).Exec(ctx); err != nil {
|
||||
return gtserror.Newf("error renaming postgres interaction requests constraint %s: %w", spec.new, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Final sqlite write-ahead-log merge.
|
||||
return doWALCheckpoint(ctx, db)
|
||||
}
|
||||
|
||||
down := func(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := Migrations.Register(up, down); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package gtsmodel
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type InteractionRequest struct {
|
||||
// Used only for migration.
|
||||
bun.BaseModel `bun:"table:new_interaction_requests"`
|
||||
|
||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`
|
||||
|
||||
// Removed in new model.
|
||||
// CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`
|
||||
|
||||
// Renamed from "StatusID" to "TargetStatusID" in new model.
|
||||
TargetStatusID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
TargetAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
InteractingAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
// Added in new model.
|
||||
InteractionRequestURI string `bun:",nullzero,notnull,unique"`
|
||||
|
||||
InteractionURI string `bun:",nullzero,notnull,unique"`
|
||||
|
||||
// Changed type from int to int16 in new model.
|
||||
InteractionType int16 `bun:",notnull"`
|
||||
|
||||
// Added in new model.
|
||||
Polite *bool `bun:",nullzero,notnull,default:false"`
|
||||
|
||||
AcceptedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
|
||||
RejectedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
|
||||
// Renamed from "URI" to "ResponseURI" in new model.
|
||||
ResponseURI string `bun:",nullzero,unique"`
|
||||
|
||||
// Added in new model.
|
||||
AuthorizationURI string `bun:",nullzero,unique"`
|
||||
}
|
||||
|
||||
const (
|
||||
LikeRequestSuffix = "#LikeRequest"
|
||||
ReplyRequestSuffix = "#ReplyRequest"
|
||||
AnnounceRequestSuffix = "#AnnounceRequest"
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package gtsmodel
|
||||
|
||||
import "time"
|
||||
|
||||
type InteractionRequest struct {
|
||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`
|
||||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"`
|
||||
StatusID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
TargetAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
InteractingAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
InteractionURI string `bun:",nullzero,notnull,unique"`
|
||||
InteractionType int `bun:",notnull"`
|
||||
AcceptedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
RejectedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
URI string `bun:",nullzero,unique"`
|
||||
}
|
||||
|
||||
const (
|
||||
InteractionLike int = 0
|
||||
InteractionReply int = 1
|
||||
InteractionAnnounce int = 2
|
||||
)
|
||||
|
|
@ -46,21 +46,7 @@ func (suite *NotificationTestSuite) spamNotifs() {
|
|||
if i%2 == 0 {
|
||||
targetAccountID = zork.ID
|
||||
} else {
|
||||
randomAssID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
targetAccountID = randomAssID
|
||||
}
|
||||
|
||||
statusID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
originAccountID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
targetAccountID = id.NewRandomULID()
|
||||
}
|
||||
|
||||
notif := >smodel.Notification{
|
||||
|
|
@ -68,8 +54,8 @@ func (suite *NotificationTestSuite) spamNotifs() {
|
|||
NotificationType: gtsmodel.NotificationFavourite,
|
||||
CreatedAt: time.Now(),
|
||||
TargetAccountID: targetAccountID,
|
||||
OriginAccountID: originAccountID,
|
||||
StatusOrEditID: statusID,
|
||||
OriginAccountID: id.NewRandomULID(),
|
||||
StatusOrEditID: id.NewRandomULID(),
|
||||
Read: util.Ptr(false),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,12 +28,17 @@ type Interaction interface {
|
|||
// GetInteractionRequestByID gets one request with the given id.
|
||||
GetInteractionRequestByID(ctx context.Context, id string) (*gtsmodel.InteractionRequest, error)
|
||||
|
||||
// GetInteractionRequestByID gets one request with the given interaction uri.
|
||||
GetInteractionRequestByInteractionURI(ctx context.Context, uri string) (*gtsmodel.InteractionRequest, error)
|
||||
// GetInteractionRequestByID gets one request with the given interaction
|
||||
// uri (ie., the URI of the requested like, reply, or announce).
|
||||
GetInteractionRequestByInteractionURI(ctx context.Context, intURI string) (*gtsmodel.InteractionRequest, error)
|
||||
|
||||
// GetInteractionRequestByURI returns one accepted or rejected
|
||||
// interaction request with the given URI, if it exists in the db.
|
||||
GetInteractionRequestByURI(ctx context.Context, uri string) (*gtsmodel.InteractionRequest, error)
|
||||
// GetInteractionRequestByResponseURI returns one accepted or rejected
|
||||
// interaction request with the given Accept or Reject URI.
|
||||
GetInteractionRequestByResponseURI(ctx context.Context, respURI string) (*gtsmodel.InteractionRequest, error)
|
||||
|
||||
// GetInteractionRequestByAuthorizationURI returns one accepted
|
||||
// interaction request with the given authorization URI.
|
||||
GetInteractionRequestByAuthorizationURI(ctx context.Context, authURI string) (*gtsmodel.InteractionRequest, error)
|
||||
|
||||
// PopulateInteractionRequest ensures that the request's struct fields are populated.
|
||||
PopulateInteractionRequest(ctx context.Context, request *gtsmodel.InteractionRequest) error
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func (d *Dereferencer) isPermittedStatus(
|
|||
switch {
|
||||
case status.Account.IsSuspended():
|
||||
// we shouldn't reach this point, log to poke devs to investigate.
|
||||
log.Warnf(ctx, "status author suspended: %s", status.AccountURI)
|
||||
log.Warnf(ctx, "should not have reached here, author suspended: %s", status.AccountURI)
|
||||
permitted = false
|
||||
|
||||
case status.InReplyToURI != "":
|
||||
|
|
@ -111,7 +111,8 @@ func (d *Dereferencer) isPermittedStatus(
|
|||
return
|
||||
}
|
||||
|
||||
// isPermittedReply ...
|
||||
// isPermittedReply checks whether the given status
|
||||
// is a permitted reply to its referenced inReplyTo.
|
||||
func (d *Dereferencer) isPermittedReply(
|
||||
ctx context.Context,
|
||||
requestUser string,
|
||||
|
|
@ -119,20 +120,21 @@ func (d *Dereferencer) isPermittedReply(
|
|||
) (bool, error) {
|
||||
|
||||
var (
|
||||
replyURI = reply.URI // Definitely set.
|
||||
inReplyToURI = reply.InReplyToURI // Definitely set.
|
||||
inReplyTo = reply.InReplyTo // Might not be set.
|
||||
replyURI = reply.URI // Definitely set.
|
||||
|
||||
parentURI = reply.InReplyToURI // Definitely set.
|
||||
parent = reply.InReplyTo // Might not be set.
|
||||
|
||||
approvedByURI = reply.ApprovedByURI // Might not be set.
|
||||
)
|
||||
|
||||
// Check if we have a stored interaction request for parent status.
|
||||
parentReq, err := d.state.DB.GetInteractionRequestByInteractionURI(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
inReplyToURI,
|
||||
parentURI,
|
||||
)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("db error getting interaction request: %w", err)
|
||||
return false, err
|
||||
return false, gtserror.Newf("db error getting interaction request: %w", err)
|
||||
}
|
||||
|
||||
// Check if we have a stored interaction request for this reply.
|
||||
|
|
@ -141,8 +143,7 @@ func (d *Dereferencer) isPermittedReply(
|
|||
replyURI,
|
||||
)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("db error getting interaction request: %w", err)
|
||||
return false, err
|
||||
return false, gtserror.Newf("db error getting interaction request: %w", err)
|
||||
}
|
||||
|
||||
parentRejected := (parentReq != nil && parentReq.IsRejected())
|
||||
|
|
@ -176,8 +177,7 @@ func (d *Dereferencer) isPermittedReply(
|
|||
// it was rejected previously and now claims
|
||||
// to be approved. Continue permission checks.
|
||||
|
||||
if inReplyTo == nil {
|
||||
|
||||
if parent == nil {
|
||||
// If we didn't have the replied-to status
|
||||
// in our database (yet), we can't check
|
||||
// right now if this reply is permitted.
|
||||
|
|
@ -191,24 +191,23 @@ func (d *Dereferencer) isPermittedReply(
|
|||
}
|
||||
|
||||
// We have the replied-to status; ensure it's fully populated.
|
||||
if err := d.state.DB.PopulateStatus(ctx, inReplyTo); err != nil {
|
||||
if err := d.state.DB.PopulateStatus(ctx, parent); err != nil {
|
||||
return false, gtserror.Newf("error populating status %s: %w", reply.ID, err)
|
||||
}
|
||||
|
||||
// Make sure replied-to status is not
|
||||
// a boost wrapper, and make sure it's
|
||||
// actually visible to the requester.
|
||||
if inReplyTo.BoostOfID != "" {
|
||||
// We do not permit replies
|
||||
// to boost wrapper statuses.
|
||||
log.Info(ctx, "rejecting reply to boost wrapper status")
|
||||
// Boost wrapper statuses
|
||||
// cannot receive replies.
|
||||
if parent.BoostOfID != "" {
|
||||
log.Warn(ctx, "received reply to boost wrapper status: %s", parent.URI)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if inReplyTo.IsLocal() {
|
||||
// If parent is a local status
|
||||
// check visibility to replyer.
|
||||
if parent.IsLocal() {
|
||||
visible, err := d.visFilter.StatusVisible(ctx,
|
||||
reply.Account,
|
||||
inReplyTo,
|
||||
parent,
|
||||
)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error checking inReplyTo visibility: %w", err)
|
||||
|
|
@ -227,12 +226,12 @@ func (d *Dereferencer) isPermittedReply(
|
|||
// approval and checking the return value.
|
||||
// No further checks are required.
|
||||
if approvedByURI != "" {
|
||||
return d.isPermittedByApprovedByIRI(
|
||||
return d.isPermittedByAuthURI(
|
||||
ctx,
|
||||
gtsmodel.InteractionReply,
|
||||
requestUser,
|
||||
reply,
|
||||
inReplyTo,
|
||||
parent,
|
||||
thisReq,
|
||||
approvedByURI,
|
||||
)
|
||||
|
|
@ -243,7 +242,7 @@ func (d *Dereferencer) isPermittedReply(
|
|||
// to see what we need to do with it.
|
||||
replyable, err := d.intFilter.StatusReplyable(ctx,
|
||||
reply.Account,
|
||||
inReplyTo,
|
||||
parent,
|
||||
)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error checking status replyability: %w", err)
|
||||
|
|
@ -260,7 +259,7 @@ func (d *Dereferencer) isPermittedReply(
|
|||
return false, d.rejectedByPolicy(
|
||||
ctx,
|
||||
reply,
|
||||
inReplyTo,
|
||||
parent,
|
||||
thisReq,
|
||||
)
|
||||
}
|
||||
|
|
@ -279,7 +278,7 @@ func (d *Dereferencer) isPermittedReply(
|
|||
// pending approval, though we know at this point
|
||||
// that the status did not include an approvedBy URI.
|
||||
|
||||
if !inReplyTo.IsLocal() {
|
||||
if !parent.IsLocal() {
|
||||
// If the replied-to status is remote, we should just
|
||||
// drop this reply at this point, as we can't verify
|
||||
// that the remote replied-to account approves it, and
|
||||
|
|
@ -359,7 +358,7 @@ func (d *Dereferencer) unpermittedByParent(
|
|||
// This collapses the chain beyond the first
|
||||
// rejected reply and allows us to avoid derefing
|
||||
// further replies we already know we don't want.
|
||||
inReplyToID := parentReq.StatusID
|
||||
inReplyToID := parentReq.TargetStatusID
|
||||
targetAccountID := parentReq.TargetAccountID
|
||||
|
||||
// As nobody is actually Rejecting the reply
|
||||
|
|
@ -369,14 +368,16 @@ func (d *Dereferencer) unpermittedByParent(
|
|||
uri := ""
|
||||
|
||||
rejection := >smodel.InteractionRequest{
|
||||
ID: rejectID,
|
||||
StatusID: inReplyToID,
|
||||
TargetAccountID: targetAccountID,
|
||||
InteractingAccountID: reply.AccountID,
|
||||
InteractionURI: reply.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
URI: uri,
|
||||
RejectedAt: time.Now(),
|
||||
ID: rejectID,
|
||||
TargetStatusID: inReplyToID,
|
||||
TargetAccountID: targetAccountID,
|
||||
InteractingAccountID: reply.AccountID,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(reply.URI, gtsmodel.ReplyRequestSuffix),
|
||||
InteractionURI: reply.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: uri,
|
||||
RejectedAt: time.Now(),
|
||||
}
|
||||
err := d.state.DB.PutInteractionRequest(ctx, rejection)
|
||||
if err != nil && !errors.Is(err, db.ErrAlreadyExists) {
|
||||
|
|
@ -386,14 +387,14 @@ func (d *Dereferencer) unpermittedByParent(
|
|||
return nil
|
||||
}
|
||||
|
||||
// isPermittedByApprovedByIRI checks whether the given URI
|
||||
// isPermittedByAuthURI checks whether the given URI
|
||||
// can be dereferenced, and whether it returns either an
|
||||
// Accept activity or an approval object which permits the
|
||||
// given reply to the given inReplyTo status.
|
||||
// Accept activity or an authorization object that permits
|
||||
// the given reply to the given inReplyTo status.
|
||||
//
|
||||
// If yes, then thisReq will be updated to
|
||||
// reflect the approval, if it's not nil.
|
||||
func (d *Dereferencer) isPermittedByApprovedByIRI(
|
||||
func (d *Dereferencer) isPermittedByAuthURI(
|
||||
ctx context.Context,
|
||||
interactionType gtsmodel.InteractionType,
|
||||
requestUser string,
|
||||
|
|
@ -402,7 +403,7 @@ func (d *Dereferencer) isPermittedByApprovedByIRI(
|
|||
thisReq *gtsmodel.InteractionRequest,
|
||||
approvedByIRI string,
|
||||
) (bool, error) {
|
||||
permitted, err := d.isValidApprovedByIRI(
|
||||
permitted, err := d.isValidAuthURI(
|
||||
ctx,
|
||||
interactionType,
|
||||
requestUser,
|
||||
|
|
@ -430,13 +431,13 @@ func (d *Dereferencer) isPermittedByApprovedByIRI(
|
|||
// pending approval, clear that now.
|
||||
reply.PendingApproval = util.Ptr(false)
|
||||
if thisReq != nil {
|
||||
thisReq.URI = approvedByIRI
|
||||
thisReq.ResponseURI = approvedByIRI
|
||||
thisReq.AcceptedAt = time.Now()
|
||||
thisReq.RejectedAt = time.Time{}
|
||||
err := d.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
thisReq,
|
||||
"uri",
|
||||
"response_uri",
|
||||
"accepted_at",
|
||||
"rejected_at",
|
||||
)
|
||||
|
|
@ -483,13 +484,13 @@ func (d *Dereferencer) rejectedByPolicy(
|
|||
// request is marked as rejected.
|
||||
thisReq.RejectedAt = time.Now()
|
||||
thisReq.AcceptedAt = time.Time{}
|
||||
thisReq.URI = rejectURI
|
||||
thisReq.ResponseURI = rejectURI
|
||||
err := d.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
thisReq,
|
||||
"rejected_at",
|
||||
"accepted_at",
|
||||
"uri",
|
||||
"response_uri",
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf("db error updating interaction request: %w", err)
|
||||
|
|
@ -501,14 +502,16 @@ func (d *Dereferencer) rejectedByPolicy(
|
|||
// We haven't stored a rejected interaction
|
||||
// request for this status yet, do it now.
|
||||
rejection := >smodel.InteractionRequest{
|
||||
ID: rejectID,
|
||||
StatusID: inReplyTo.ID,
|
||||
TargetAccountID: inReplyTo.AccountID,
|
||||
InteractingAccountID: reply.AccountID,
|
||||
InteractionURI: reply.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
URI: rejectURI,
|
||||
RejectedAt: time.Now(),
|
||||
ID: rejectID,
|
||||
TargetStatusID: inReplyTo.ID,
|
||||
TargetAccountID: inReplyTo.AccountID,
|
||||
InteractingAccountID: reply.AccountID,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(reply.URI, gtsmodel.ReplyRequestSuffix),
|
||||
InteractionURI: reply.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: rejectURI,
|
||||
RejectedAt: time.Now(),
|
||||
}
|
||||
err := d.state.DB.PutInteractionRequest(ctx, rejection)
|
||||
if err != nil && !errors.Is(err, db.ErrAlreadyExists) {
|
||||
|
|
@ -611,7 +614,7 @@ func (d *Dereferencer) isPermittedBoost(
|
|||
// Boost claims to be approved, check
|
||||
// this by dereferencing the approvedBy
|
||||
// and inspecting the return value.
|
||||
permitted, err := d.isValidApprovedByIRI(
|
||||
permitted, err := d.isValidAuthURI(
|
||||
ctx,
|
||||
gtsmodel.InteractionAnnounce,
|
||||
requestUser,
|
||||
|
|
@ -637,36 +640,36 @@ func (d *Dereferencer) isPermittedBoost(
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// isValidApprovedByIRI dereferences the activitystreams Accept or approval
|
||||
// at the specified IRI, and checks the Accept or approval for validity
|
||||
// against the provided expectedActor, expectedObject, and expectedTarget.
|
||||
// isValidAuthURI dereferences the activitystreams Accept or authorization
|
||||
// at the specified IRI, and checks it for validity against the provided
|
||||
// expectedActor, expectedObject, and expectedTarget.
|
||||
//
|
||||
// Will return either (true, nil) if everything looked OK, an error
|
||||
// if something went wrong internally during deref, or (false, nil)
|
||||
// if the dereferenced Accept/Approval did not meet expectations.
|
||||
func (d *Dereferencer) isValidApprovedByIRI(
|
||||
func (d *Dereferencer) isValidAuthURI(
|
||||
ctx context.Context,
|
||||
interactionType gtsmodel.InteractionType,
|
||||
requestUser string,
|
||||
approvedByIRIStr string, // approval uri Eg., "https://example.org/users/someone/accepts/01J2736AWWJ3411CPR833F6D03"
|
||||
authIRIStr string, // authorization uri Eg., "https://example.org/users/someone/accepts/01J2736AWWJ3411CPR833F6D03"
|
||||
expectActorURIStr string, // actor Eg., "https://example.org/users/someone"
|
||||
expectObjectURIStr string, // object Eg., "https://some.instance.example.org/users/someone_else/statuses/01J27414TWV9F7DC39FN8ABB5R"
|
||||
expectTargetURIStr string, // target Eg., "https://example.org/users/someone/statuses/01JM4REQTJ1BZ1R4BPYP1W4R9E"
|
||||
) (bool, error) {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithField("approvedByIRI", approvedByIRIStr)
|
||||
WithField("authIRI", authIRIStr)
|
||||
|
||||
approvedByIRI, err := url.Parse(approvedByIRIStr)
|
||||
authIRI, err := url.Parse(authIRIStr)
|
||||
if err != nil {
|
||||
// Real returnable error.
|
||||
err := gtserror.Newf("error parsing approvedByIRI: %w", err)
|
||||
err := gtserror.Newf("error parsing authIRI: %w", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Don't make calls to the IRI if its
|
||||
// domain is blocked, just return false.
|
||||
blocked, err := d.state.DB.IsDomainBlocked(ctx, approvedByIRI.Host)
|
||||
blocked, err := d.state.DB.IsDomainBlocked(ctx, authIRI.Host)
|
||||
if err != nil {
|
||||
// Real returnable error.
|
||||
err := gtserror.Newf("error checking domain block: %w", err)
|
||||
|
|
@ -674,7 +677,7 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
}
|
||||
|
||||
if blocked {
|
||||
l.Info("approvedByIRI host is blocked")
|
||||
l.Info("authIRI host is blocked")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
@ -685,12 +688,12 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
return false, err
|
||||
}
|
||||
|
||||
// Make the call to the approvedByURI.
|
||||
// Make the call to the authIRI.
|
||||
// Log any error encountered here but don't
|
||||
// return it as it's not *our* error.
|
||||
rsp, err := tsport.Dereference(ctx, approvedByIRI)
|
||||
rsp, err := tsport.Dereference(ctx, authIRI)
|
||||
if err != nil {
|
||||
l.Errorf("error dereferencing approvedByIRI: %v", err)
|
||||
l.Errorf("error dereferencing authIRI: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
@ -706,31 +709,31 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
}
|
||||
|
||||
// Extract the URI/ID of the type.
|
||||
approvedByID := ap.GetJSONLDId(t)
|
||||
approvedByIDStr := approvedByID.String()
|
||||
authID := ap.GetJSONLDId(t)
|
||||
authIDStr := authID.String()
|
||||
|
||||
// Check whether input URI and final returned URI
|
||||
// have changed (i.e. we followed some redirects).
|
||||
rspURL := rsp.Request.URL
|
||||
rspURLStr := rspURL.String()
|
||||
if rspURLStr != approvedByIRIStr {
|
||||
if rspURLStr != authIRIStr {
|
||||
// If rspURLStr != approvedByIRI, make sure final
|
||||
// response URL is at least on the same host as
|
||||
// what we expected (ie., we weren't redirected
|
||||
// across domains), and make sure it's the same
|
||||
// as the ID of the Accept we were returned.
|
||||
switch {
|
||||
case rspURL.Host != approvedByIRI.Host:
|
||||
case rspURL.Host != authIRI.Host:
|
||||
l.Errorf(
|
||||
"final deref host %s did not match approvedByIRI host",
|
||||
"final deref host %s did not match authIRI host",
|
||||
rspURL.Host,
|
||||
)
|
||||
return false, nil
|
||||
|
||||
case approvedByIDStr != rspURLStr:
|
||||
case authIDStr != rspURLStr:
|
||||
l.Errorf(
|
||||
"final deref uri %s did not match returned ID %s",
|
||||
rspURLStr, approvedByIDStr,
|
||||
rspURLStr, authIDStr,
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -739,13 +742,13 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
// Response is superficially OK,
|
||||
// check in more detail now.
|
||||
|
||||
// First try to parse type as Approval stamp.
|
||||
if approvable, ok := ap.ToApprovable(t); ok {
|
||||
return isValidApprovable(
|
||||
// First try to parse type as Authorization stamp.
|
||||
if authable, ok := ap.ToAuthorizationable(t); ok {
|
||||
return isValidAuthorization(
|
||||
ctx,
|
||||
interactionType,
|
||||
approvable,
|
||||
approvedByID,
|
||||
authable,
|
||||
authID,
|
||||
expectActorURIStr, // actor
|
||||
expectObjectURIStr, // object
|
||||
expectTargetURIStr, // target
|
||||
|
|
@ -757,7 +760,7 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
return isValidAcceptable(
|
||||
ctx,
|
||||
acceptable,
|
||||
approvedByID,
|
||||
authID,
|
||||
expectActorURIStr, // actor
|
||||
expectObjectURIStr, // object
|
||||
expectTargetURIStr, // target
|
||||
|
|
@ -767,8 +770,8 @@ func (d *Dereferencer) isValidApprovedByIRI(
|
|||
// Type wasn't something we
|
||||
// could do anything with!
|
||||
l.Errorf(
|
||||
"%T at %s not approvable or acceptable",
|
||||
t, approvedByIRIStr,
|
||||
"%T at %s not authorization or accept",
|
||||
t, authIRIStr,
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -850,55 +853,55 @@ func isValidAcceptable(
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func isValidApprovable(
|
||||
func isValidAuthorization(
|
||||
ctx context.Context,
|
||||
interactionType gtsmodel.InteractionType,
|
||||
approvable ap.Approvable,
|
||||
approvalID *url.URL,
|
||||
auth ap.Authorizationable,
|
||||
authID *url.URL,
|
||||
expectActorURIStr string, // actor Eg., "https://example.org/users/someone"
|
||||
expectObjectURIStr string, // object Eg., "https://some.instance.example.org/users/someone_else/statuses/01J27414TWV9F7DC39FN8ABB5R"
|
||||
expectTargetURIStr string, // target Eg., "https://example.org/users/someone/statuses/01JM4REQTJ1BZ1R4BPYP1W4R9E"
|
||||
) (bool, error) {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithField("approval", approvalID.String())
|
||||
WithField("auth", authID.String())
|
||||
|
||||
// Check that the type of the Approval
|
||||
// Check that the type of the Authorization
|
||||
// matches the interaction it's approving.
|
||||
switch tn := approvable.GetTypeName(); {
|
||||
case (tn == ap.ObjectLikeApproval && interactionType == gtsmodel.InteractionLike),
|
||||
(tn == ap.ObjectReplyApproval && interactionType == gtsmodel.InteractionReply),
|
||||
(tn == ap.ObjectAnnounceApproval && interactionType == gtsmodel.InteractionAnnounce):
|
||||
switch tn := auth.GetTypeName(); {
|
||||
case (tn == ap.ObjectLikeAuthorization && interactionType == gtsmodel.InteractionLike),
|
||||
(tn == ap.ObjectReplyAuthorization && interactionType == gtsmodel.InteractionReply),
|
||||
(tn == ap.ObjectAnnounceAuthorization && interactionType == gtsmodel.InteractionAnnounce):
|
||||
// All good baby!
|
||||
default:
|
||||
// There's a mismatch.
|
||||
l.Errorf(
|
||||
"approval type %s cannot approve %s",
|
||||
"authorization type %s cannot approve %s",
|
||||
tn, interactionType.String(),
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Extract the actor IRI and string from Approval.
|
||||
actorIRIs := ap.GetAttributedTo(approvable)
|
||||
actorIRIs := ap.GetAttributedTo(auth)
|
||||
actorIRI, actorIRIStr := extractIRI(actorIRIs)
|
||||
switch {
|
||||
case actorIRIStr == "":
|
||||
l.Error("Approval missing attributedTo IRI")
|
||||
l.Error("authorization missing attributedTo IRI")
|
||||
return false, nil
|
||||
|
||||
// Ensure the Approval actor is on
|
||||
// Ensure the authorization actor is on
|
||||
// the instance hosting the Approval.
|
||||
case actorIRI.Host != approvalID.Host:
|
||||
case actorIRI.Host != authID.Host:
|
||||
l.Errorf(
|
||||
"actor %s not on the same host as Approval",
|
||||
"actor %s not on the same host as authorization",
|
||||
actorIRIStr,
|
||||
)
|
||||
return false, nil
|
||||
|
||||
// Ensure the Approval actor is who we expect
|
||||
// Ensure the auth actor is who we expect
|
||||
// it to be, and not someone else trying to
|
||||
// do an Approval for an interaction with a
|
||||
// do an auth for an interaction with a
|
||||
// statusable they don't own.
|
||||
case actorIRIStr != expectActorURIStr:
|
||||
l.Errorf(
|
||||
|
|
@ -908,33 +911,32 @@ func isValidApprovable(
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// Extract the object IRI string from Approval.
|
||||
objectIRIs := ap.GetObjectIRIs(approvable)
|
||||
// Extract the object IRI string from authorization.
|
||||
objectIRIs := ap.GetInteractingObject(auth)
|
||||
_, objectIRIStr := extractIRI(objectIRIs)
|
||||
switch {
|
||||
case objectIRIStr == "":
|
||||
l.Error("missing Approval object IRI")
|
||||
l.Error("missing authorization interactingObject IRI")
|
||||
return false, nil
|
||||
|
||||
// Ensure the Approval Object is what we expect
|
||||
// Ensure the authorization object is what we expect
|
||||
// it to be, ie., it's approving the interaction
|
||||
// we need it to approve, and not something else.
|
||||
case objectIRIStr != expectObjectURIStr:
|
||||
l.Errorf(
|
||||
"resolved Approval object IRI %s was not the same as expected object %s",
|
||||
"resolved authorization interactingObject IRI %s was not the same as expected object %s",
|
||||
objectIRIStr, expectObjectURIStr,
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// If there's a Target set then verify it's
|
||||
// what we expect it to be, ie., it should point
|
||||
// back to the post that's being interacted with.
|
||||
targetIRIs := ap.GetTargetIRIs(approvable)
|
||||
// Ensure the authorization target is what we expect,
|
||||
// ie., it should be the status being interacted with.
|
||||
targetIRIs := ap.GetInteractionTarget(auth)
|
||||
_, targetIRIStr := extractIRI(targetIRIs)
|
||||
if targetIRIStr != "" && targetIRIStr != expectTargetURIStr {
|
||||
l.Errorf(
|
||||
"resolved Approval target IRI %s was not the same as expected target %s",
|
||||
"resolved authorization interactionTarget IRI %s was not the same as expected target %s",
|
||||
targetIRIStr, expectTargetURIStr,
|
||||
)
|
||||
return false, nil
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithTag() {
|
|||
// status values should be set
|
||||
suite.Equal("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7", status.URI)
|
||||
suite.Equal("https://unknown-instance.com/users/@brand_new_person/01H641QSRS3TCXSVC10X4GPKW7", status.URL)
|
||||
suite.Equal("<p>Babe are you okay, you've hardly touched your <a href=\"https://unknown-instance.com/tags/piss\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>piss</span></a></p>", status.Content)
|
||||
suite.Equal("<p><span class=\"h-card\"><a href=\"http://fossbros-anonymous.io/@foss_satan\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>foss_satan</span></a></span>Babe are you okay, you've hardly touched your <a href=\"https://unknown-instance.com/tags/piss\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>piss</span></a></p>", status.Content)
|
||||
suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI)
|
||||
suite.False(*status.Local)
|
||||
suite.Empty(status.ContentWarning)
|
||||
|
|
|
|||
|
|
@ -42,18 +42,14 @@ func (suite *FederatingActorTestSuite) TestSendNoRemoteFollowers() {
|
|||
ctx := suite.T().Context()
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
testNote := testrig.NewAPNote(
|
||||
testrig.URLMustParse("http://localhost:8080/users/the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
testrig.URLMustParse("http://localhost:8080/@the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
time.Now(),
|
||||
"boobies",
|
||||
"",
|
||||
testrig.URLMustParse(testAccount.URI),
|
||||
[]*url.URL{testrig.URLMustParse(testAccount.FollowersURI)},
|
||||
nil,
|
||||
false,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
&testrig.NewAPNoteParams{
|
||||
ID: testrig.URLMustParse("http://localhost:8080/users/the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
URL: testrig.URLMustParse("http://localhost:8080/@the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
CreatedAt: time.Now(),
|
||||
Content: "boobies",
|
||||
AttributedTo: testrig.URLMustParse(testAccount.URI),
|
||||
To: []*url.URL{testrig.URLMustParse(testAccount.FollowersURI)},
|
||||
},
|
||||
)
|
||||
testActivity := testrig.WrapAPNoteInCreate(testrig.URLMustParse("http://localhost:8080/whatever_some_create"), testrig.URLMustParse(testAccount.URI), time.Now(), testNote)
|
||||
|
||||
|
|
@ -98,18 +94,14 @@ func (suite *FederatingActorTestSuite) TestSendRemoteFollower() {
|
|||
suite.NoError(err)
|
||||
|
||||
testNote := testrig.NewAPNote(
|
||||
testrig.URLMustParse("http://localhost:8080/users/the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
testrig.URLMustParse("http://localhost:8080/@the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
testrig.TimeMustParse("2022-06-02T12:22:21+02:00"),
|
||||
"boobies",
|
||||
"",
|
||||
testrig.URLMustParse(testAccount.URI),
|
||||
[]*url.URL{testrig.URLMustParse(testAccount.FollowersURI)},
|
||||
nil,
|
||||
false,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
&testrig.NewAPNoteParams{
|
||||
ID: testrig.URLMustParse("http://localhost:8080/users/the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
URL: testrig.URLMustParse("http://localhost:8080/@the_mighty_zork/statuses/01G1TR6BADACCZWQMNF9X21TV5"),
|
||||
CreatedAt: testrig.TimeMustParse("2022-06-02T12:22:21+02:00"),
|
||||
Content: "boobies",
|
||||
AttributedTo: testrig.URLMustParse(testAccount.URI),
|
||||
To: []*url.URL{testrig.URLMustParse(testAccount.FollowersURI)},
|
||||
},
|
||||
)
|
||||
testActivity := testrig.WrapAPNoteInCreate(testrig.URLMustParse("http://localhost:8080/whatever_some_create"), testrig.URLMustParse(testAccount.URI), testrig.TimeMustParse("2022-06-02T12:22:21+02:00"), testNote)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
|
|
@ -39,7 +40,7 @@ func (f *DB) GetAccept(
|
|||
ctx context.Context,
|
||||
acceptIRI *url.URL,
|
||||
) (vocab.ActivityStreamsAccept, error) {
|
||||
approval, err := f.state.DB.GetInteractionRequestByURI(ctx, acceptIRI.String())
|
||||
approval, err := f.state.DB.GetInteractionRequestByResponseURI(ctx, acceptIRI.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -63,9 +64,9 @@ func (f *DB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) err
|
|||
return nil
|
||||
}
|
||||
|
||||
// Ensure an activity ID is given.
|
||||
acceptID := ap.GetJSONLDId(accept)
|
||||
if acceptID == nil {
|
||||
// We need an ID.
|
||||
const text = "Accept had no id property"
|
||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
|
|
@ -109,7 +110,7 @@ func (f *DB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) err
|
|||
case name == ap.ActivityLike:
|
||||
objIRI := ap.GetJSONLDId(asType)
|
||||
if objIRI == nil {
|
||||
log.Debugf(ctx, "could not retrieve id of inlined Accept object %s", name)
|
||||
log.Warnf(ctx, "missing id for inlined object %s: %s", name, acceptID)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ func (f *DB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) err
|
|||
case name == ap.ActivityAnnounce || ap.IsStatusable(name):
|
||||
objIRI := ap.GetJSONLDId(asType)
|
||||
if objIRI == nil {
|
||||
log.Debugf(ctx, "could not retrieve id of inlined Accept object %s", name)
|
||||
log.Warnf(ctx, "missing id for inlined object %s: %s", name, acceptID)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -146,9 +147,38 @@ func (f *DB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) err
|
|||
return err
|
||||
}
|
||||
|
||||
// Todo: ACCEPT POLITE INLINED LIKE REQUEST.
|
||||
//
|
||||
// Implement this when we start
|
||||
// sending out polite LikeRequests.
|
||||
|
||||
// ACCEPT POLITE INLINED REPLY REQUEST
|
||||
case name == ap.ActivityReplyRequest:
|
||||
replyReq, ok := asType.(vocab.GoToSocialReplyRequest)
|
||||
if !ok {
|
||||
const text = "malformed ReplyRequest as object of Accept"
|
||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
|
||||
if err := f.acceptPoliteReplyRequest(
|
||||
ctx,
|
||||
acceptID,
|
||||
accept,
|
||||
replyReq,
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Todo: ACCEPT POLITE INLINED ANNOUNCE REQUEST
|
||||
//
|
||||
// Implement this when we start
|
||||
// sending out polite AnnounceRequests.
|
||||
|
||||
// UNHANDLED
|
||||
default:
|
||||
log.Debugf(ctx, "unhandled object type: %s", name)
|
||||
log.Debugf(ctx, "unhandled object type %s: %s", name, acceptID)
|
||||
}
|
||||
|
||||
} else if object.IsIRI() {
|
||||
|
|
@ -445,8 +475,7 @@ func (f *DB) acceptStoredStatus(
|
|||
// Mark the status as approved by this URI.
|
||||
status.PendingApproval = util.Ptr(false)
|
||||
status.ApprovedByURI = approvedByURI.String()
|
||||
if err := f.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
if err := f.state.DB.UpdateStatus(ctx,
|
||||
status,
|
||||
"pending_approval",
|
||||
"approved_by_uri",
|
||||
|
|
@ -543,8 +572,7 @@ func (f *DB) acceptLikeIRI(
|
|||
// Mark the fave as approved by this URI.
|
||||
fave.PendingApproval = util.Ptr(false)
|
||||
fave.ApprovedByURI = approvedByURI.String()
|
||||
if err := f.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
if err := f.state.DB.UpdateStatusFave(ctx,
|
||||
fave,
|
||||
"pending_approval",
|
||||
"approved_by_uri",
|
||||
|
|
@ -566,6 +594,316 @@ func (f *DB) acceptLikeIRI(
|
|||
return nil
|
||||
}
|
||||
|
||||
// partialAcceptInteractionRequest represents a
|
||||
// partially-parsed accept of an interaction request
|
||||
// returned from parseAcceptInteractionRequestable.
|
||||
type partialAcceptInteractionRequest struct {
|
||||
intReqURI *url.URL
|
||||
actorURI *url.URL
|
||||
parentURI *url.URL
|
||||
instrumentURI *url.URL
|
||||
authURI *url.URL
|
||||
intReq *gtsmodel.InteractionRequest // May be nil.
|
||||
}
|
||||
|
||||
// parseAcceptInteractionRequestable does some initial parsing
|
||||
// and validation of the given Accept with inlined polite
|
||||
// interaction request (LikeRequest, ReplyRequest, AnnounceRequest).
|
||||
//
|
||||
// Will return nil, nil if there's no need for further processing.
|
||||
func (f *DB) parseAcceptInteractionRequestable(
|
||||
ctx context.Context,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
intRequestable ap.InteractionRequestable,
|
||||
receivingAcct *gtsmodel.Account,
|
||||
requestingAcct *gtsmodel.Account,
|
||||
) (*partialAcceptInteractionRequest, error) {
|
||||
intReqURI := ap.GetJSONLDId(intRequestable)
|
||||
if intReqURI == nil {
|
||||
const text = "no id set on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
|
||||
// Ensure we have actor IRI on
|
||||
// the interaction requestable.
|
||||
actors := ap.GetActorIRIs(intRequestable)
|
||||
if len(actors) != 1 {
|
||||
const text = "invalid or missing actor property on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
actorURI := actors[0]
|
||||
|
||||
// Ensure we have an object URI, which
|
||||
// should point to the statusable being
|
||||
// interacted with, ie., the parent status.
|
||||
objects := ap.GetObjectIRIs(intRequestable)
|
||||
if len(objects) != 1 {
|
||||
const text = "invalid or missing object property on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
parentURI := objects[0]
|
||||
|
||||
// Ensure we have instrument, which should
|
||||
// be or point to the activity/object that
|
||||
// interacts with the parent status.
|
||||
instruments := ap.ExtractInstruments(intRequestable)
|
||||
if len(instruments) != 1 {
|
||||
const text = "invalid or missing instrument property on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
instrument := instruments[0]
|
||||
|
||||
// We just need the URI for the instrument,
|
||||
// not the whole type, which we can either
|
||||
// fetch from remote or get locally.
|
||||
var instrumentURI *url.URL
|
||||
if instrument.IsIRI() {
|
||||
instrumentURI = instrument.GetIRI()
|
||||
} else {
|
||||
t := instrument.GetType()
|
||||
if t == nil {
|
||||
const text = "nil instrument type on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
instrumentURI = ap.GetJSONLDId(t)
|
||||
}
|
||||
|
||||
// Ensure we have result URI, which should
|
||||
// point to an authorization for this interaction.
|
||||
results := ap.GetResultIRIs(accept)
|
||||
if len(results) != 1 {
|
||||
const text = "invalid or missing result property on embedded interaction request"
|
||||
return nil, gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
authURI := results[0]
|
||||
|
||||
// Check if we have a gtsmodel interaction
|
||||
// request already stored for this interaction.
|
||||
intReq, err := f.state.DB.GetInteractionRequestByInteractionURI(ctx, instrumentURI.String())
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
// Real db error.
|
||||
return nil, gtserror.Newf("db error getting interaction request: %w", err)
|
||||
}
|
||||
|
||||
if intReq == nil {
|
||||
|
||||
// No request stored for this interaction.
|
||||
// Means this is *probably* a remote interaction
|
||||
// with a remote status. Double check this.
|
||||
host := config.GetHost()
|
||||
acctDomain := config.GetAccountDomain()
|
||||
if instrumentURI.Host == host ||
|
||||
instrumentURI.Host == acctDomain ||
|
||||
intReqURI.Host == host ||
|
||||
intReqURI.Host == acctDomain {
|
||||
// Claims to be Accepting something of ours,
|
||||
// but we don't have an interaction request
|
||||
// stored. Most likely it's been deleted in
|
||||
// the meantime, or this is a mistake. Bail.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// This must be an Accept of a remote interaction
|
||||
// request. Ensure relevance of this message by
|
||||
// checking that receiver follows requester.
|
||||
following, err := f.state.DB.IsFollowing(
|
||||
ctx,
|
||||
receivingAcct.ID,
|
||||
requestingAcct.ID,
|
||||
)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("db error checking following: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
if !following {
|
||||
// If we don't follow this person, and
|
||||
// they're not Accepting something we
|
||||
// created, then we don't care.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Request stored for this interaction URI.
|
||||
//
|
||||
// Note: this path is not actually possible until v0.21.0,
|
||||
// because we don't send out polite requests yet in v0.20.0.
|
||||
|
||||
// If the request is already accepted,
|
||||
// we don't need to do anything at all.
|
||||
if intReq.IsAccepted() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// The person doing the Accept must be the
|
||||
// same as the target of the interaction request.
|
||||
if intReq.TargetAccountID != requestingAcct.ID {
|
||||
const text = "cannot Accept interaction request on another actor's behalf"
|
||||
return nil, gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// The stored interaction request and the inlined
|
||||
// interaction request must have the same target status.
|
||||
if intReq.TargetStatus.URI != parentURI.String() {
|
||||
const text = "Accept interaction request mismatched object URI"
|
||||
return nil, gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// The stored interaction request and the inlined
|
||||
// interaction request must have the same URI.
|
||||
if intReq.InteractionRequestURI != intReqURI.String() {
|
||||
const text = "Accept interaction request mismatched id"
|
||||
return nil, gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the things.
|
||||
return &partialAcceptInteractionRequest{
|
||||
intReqURI: intReqURI,
|
||||
actorURI: actorURI,
|
||||
parentURI: parentURI,
|
||||
instrumentURI: instrumentURI,
|
||||
authURI: authURI,
|
||||
intReq: intReq, // May be nil.
|
||||
}, nil
|
||||
}
|
||||
|
||||
// acceptPoliteReplyRequest handles the Accept of a polite ReplyRequest,
|
||||
// ie., something that looks like this:
|
||||
//
|
||||
// {
|
||||
// "@context": [
|
||||
// "https://www.w3.org/ns/activitystreams",
|
||||
// "https://gotosocial.org/ns"
|
||||
// ],
|
||||
// "type": "Accept",
|
||||
// "to": "https://example.com/users/bob",
|
||||
// "id": "https://example.com/users/alice/activities/1234",
|
||||
// "actor": "https://example.com/users/alice",
|
||||
// "object": {
|
||||
// "type": "ReplyRequest",
|
||||
// "id": "https://example.com/users/bob/interaction_requests/12345",
|
||||
// "actor": "https://example.com/users/bob",
|
||||
// "object": "https://example.com/users/alice/statuses/1",
|
||||
// "instrument": "https://example.org/users/bob/statuses/12345"
|
||||
// },
|
||||
// "result": "https://example.com/users/alice/authorizations/1"
|
||||
// }
|
||||
func (f *DB) acceptPoliteReplyRequest(
|
||||
ctx context.Context,
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
replyRequest vocab.GoToSocialReplyRequest,
|
||||
receivingAcct *gtsmodel.Account,
|
||||
requestingAcct *gtsmodel.Account,
|
||||
) error {
|
||||
// Parse out the Accept and
|
||||
// embedded interaction requestable.
|
||||
partial, err := f.parseAcceptInteractionRequestable(
|
||||
ctx,
|
||||
accept,
|
||||
replyRequest,
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if partial == nil {
|
||||
// Nothing to do!
|
||||
return nil
|
||||
}
|
||||
|
||||
if partial.intReq == nil {
|
||||
// This is a remote accept of a remote reply.
|
||||
//
|
||||
// Process dereferencing etc asynchronously, leaving
|
||||
// the interaction request as nil. We don't need to
|
||||
// create an int req for remote accepts of remote
|
||||
// replies, we can just validate + store the auth URI.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APObjectType: ap.ActivityReplyRequest,
|
||||
APActivityType: ap.ActivityAccept,
|
||||
APIRI: partial.authURI,
|
||||
APObject: partial.instrumentURI,
|
||||
Receiving: receivingAcct,
|
||||
Requesting: requestingAcct,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// We already have a request stored for this interaction.
|
||||
//
|
||||
// Note: this path is not actually possible until v0.21.0,
|
||||
// because we don't send out polite requests yet in v0.20.0.
|
||||
|
||||
// Make sure the stored interaction request
|
||||
// lines up with the Accept ReplyRequest.
|
||||
if partial.intReq.InteractionType != gtsmodel.InteractionReply {
|
||||
const text = "Accept ReplyRequest targets interaction request that isn't of type Reply"
|
||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
}
|
||||
|
||||
// The stored reply must be the same as
|
||||
// the instrument of the ReplyRequest.
|
||||
reply := partial.intReq.Reply
|
||||
if reply.URI != partial.instrumentURI.String() {
|
||||
const text = "Accept ReplyRequest mismatched instrument URI"
|
||||
return gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// The actor of the stored reply must be the
|
||||
// same as the actor of the ReplyRequest.
|
||||
if reply.AccountURI != partial.actorURI.String() {
|
||||
const text = "Accept ReplyRequest mismatched actor URI"
|
||||
return gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// This all looks good, we can update the
|
||||
// interaction request and stored reply.
|
||||
unlock := f.state.FedLocks.Lock(partial.intReq.InteractionURI)
|
||||
defer unlock()
|
||||
|
||||
authURIStr := partial.authURI.String()
|
||||
partial.intReq.AcceptedAt = time.Now()
|
||||
partial.intReq.AuthorizationURI = authURIStr
|
||||
partial.intReq.ResponseURI = acceptID.String()
|
||||
if err := f.state.DB.UpdateInteractionRequest(
|
||||
ctx, partial.intReq,
|
||||
"accepted_at",
|
||||
"authorization_uri",
|
||||
"response_uri",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating interaction request: %w", err)
|
||||
}
|
||||
|
||||
reply.ApprovedByURI = authURIStr
|
||||
reply.PendingApproval = util.Ptr(false)
|
||||
if err := f.state.DB.UpdateStatus(
|
||||
ctx, reply,
|
||||
"approved_by_uri",
|
||||
"pending_approval",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating status: %w", err)
|
||||
}
|
||||
|
||||
// Handle any remaining side effects in the processor.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APObjectType: ap.ActivityReplyRequest,
|
||||
APActivityType: ap.ActivityAccept,
|
||||
APIRI: partial.authURI,
|
||||
APObject: partial.instrumentURI,
|
||||
GTSModel: partial.intReq,
|
||||
Receiving: receivingAcct,
|
||||
Requesting: requestingAcct,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// approvedByURI extracts the appropriate *url.URL
|
||||
// to use as an interaction's approvedBy value by
|
||||
// checking to see if the Accept has a result URL set.
|
||||
|
|
@ -577,11 +915,8 @@ func (f *DB) acceptLikeIRI(
|
|||
// Error is only returned if the result URI is set
|
||||
// but the host differs from the Accept ID host.
|
||||
//
|
||||
// TODO: This function should be updated at some point
|
||||
// to check for inlined result type, and see if type is
|
||||
// a LikeApproval, ReplyApproval, or AnnounceApproval,
|
||||
// and check the attributedTo, object, and target of
|
||||
// the approval as well. But this'll do for now.
|
||||
// TODO: This function could be updated at some
|
||||
// point to check for inlined result type.
|
||||
func approvedByURI(
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
|
|
@ -623,11 +958,7 @@ func approvedByURI(
|
|||
|
||||
if resultIRI.Host != acceptID.Host {
|
||||
// What the boobs is this?
|
||||
err := fmt.Errorf(
|
||||
"host of result %s differed from host of Accept %s",
|
||||
resultIRI, accept,
|
||||
)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("host of result %s differed from host of Accept %s", resultIRI, accept)
|
||||
}
|
||||
|
||||
// Use the result IRI we've been
|
||||
|
|
|
|||
120
internal/federation/federatingdb/accept_test.go
Normal file
120
internal/federation/federatingdb/accept_test.go
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package federatingdb_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/messages"
|
||||
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
const (
|
||||
rMediaPath = "../../../testrig/media"
|
||||
rTemplatePath = "../../../web/template"
|
||||
)
|
||||
|
||||
type AcceptTestSuite struct {
|
||||
FederatingDBTestSuite
|
||||
}
|
||||
|
||||
func (suite *AcceptTestSuite) TestAcceptRemoteReplyRequest() {
|
||||
// Accept of a reply by
|
||||
// brand_new_person to foss_satan.
|
||||
const acceptJSON = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns"
|
||||
],
|
||||
"type": "Accept",
|
||||
"to": "https://unknown-instance.com/users/brand_new_person",
|
||||
"cc": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"id": "http://fossbros-anonymous.io/users/foss_satan/accepts/1234",
|
||||
"actor": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"object": {
|
||||
"type": "ReplyRequest",
|
||||
"id": "https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7/replyRequest",
|
||||
"actor": "https://unknown-instance.com/users/brand_new_person",
|
||||
"object": "http://fossbros-anonymous.io/users/foss_satan/statuses/01FVW7JHQFSFK166WWKR8CBA6M",
|
||||
"instrument": "https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"
|
||||
},
|
||||
"result": "http://fossbros-anonymous.io/users/foss_satan/authorizations/1234"
|
||||
}`
|
||||
|
||||
// The accept will be delivered by foss_satan to zork.
|
||||
ctx := createTestContext(
|
||||
suite.T(),
|
||||
suite.testAccounts["local_account_1"],
|
||||
suite.testAccounts["remote_account_1"],
|
||||
)
|
||||
|
||||
// Have zork follow foss_satan for this test,
|
||||
// else the message will be scattered unto the four winds.
|
||||
follow := >smodel.Follow{
|
||||
ID: "01K4STEH5NWAXBZ4TFNGQQQ984",
|
||||
CreatedAt: testrig.TimeMustParse("2022-05-14T13:21:09+02:00"),
|
||||
UpdatedAt: testrig.TimeMustParse("2022-05-14T13:21:09+02:00"),
|
||||
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
|
||||
TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
||||
URI: "http://localhost:8080/users/the_mighty_zork/follow/01G1TK3PQKFW1BQZ9WVYRTFECK",
|
||||
}
|
||||
if err := suite.state.DB.PutFollow(ctx, follow); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Parse accept into vocab.Type.
|
||||
t, err := ap.DecodeType(ctx, io.NopCloser(bytes.NewBufferString(acceptJSON)))
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
accept := t.(vocab.ActivityStreamsAccept)
|
||||
|
||||
// Process the accept.
|
||||
if err := suite.federatingDB.Accept(ctx, accept); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// There should be an accept msg
|
||||
// heading to the processor now.
|
||||
msg, ok := suite.state.Workers.Federator.Queue.PopCtx(ctx)
|
||||
if !ok {
|
||||
suite.FailNow("no message in queue")
|
||||
}
|
||||
|
||||
suite.EqualValues(
|
||||
&messages.FromFediAPI{
|
||||
APObjectType: "ReplyRequest",
|
||||
APActivityType: "Accept",
|
||||
APIRI: testrig.URLMustParse("http://fossbros-anonymous.io/users/foss_satan/authorizations/1234"),
|
||||
APObject: testrig.URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"),
|
||||
Requesting: suite.testAccounts["remote_account_1"],
|
||||
Receiving: suite.testAccounts["local_account_1"],
|
||||
},
|
||||
msg,
|
||||
)
|
||||
}
|
||||
|
||||
func TestAcceptTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AcceptTestSuite))
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ func (f *DB) Block(ctx context.Context, blockable vocab.ActivityStreamsBlock) er
|
|||
requesting := activityContext.requestingAcct
|
||||
receiving := activityContext.receivingAcct
|
||||
|
||||
if receiving.IsMoving() {
|
||||
if requesting.IsMoving() {
|
||||
// A Moving account
|
||||
// can't do this.
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -281,43 +281,18 @@ func (f *DB) createStatusable(
|
|||
statusable ap.Statusable,
|
||||
forwarded bool,
|
||||
) error {
|
||||
// Check whether this status is both
|
||||
// relevant, and doesn't look like spam.
|
||||
err := f.spamFilter.StatusableOK(ctx,
|
||||
receiver,
|
||||
requester,
|
||||
statusable,
|
||||
)
|
||||
// Check for spam / relevance.
|
||||
ok, err := f.statusableOK(ctx, receiver, requester, statusable)
|
||||
if err != nil {
|
||||
// Error already
|
||||
// wrapped.
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case err == nil:
|
||||
// No problem!
|
||||
|
||||
case gtserror.IsNotRelevant(err):
|
||||
// This case is quite common if a remote (Mastodon)
|
||||
// instance forwards a message to us which is a reply
|
||||
// from someone else to a status we've also replied to.
|
||||
//
|
||||
// It does this to try to ensure thread completion, but
|
||||
// we have our own thread fetching mechanism anyway.
|
||||
log.Debugf(ctx, "status %s is not relevant to receiver (%v); dropping it",
|
||||
ap.GetJSONLDId(statusable), err,
|
||||
)
|
||||
if !ok {
|
||||
// Not relevant / spam.
|
||||
// Already logged.
|
||||
return nil
|
||||
|
||||
case gtserror.IsSpam(err):
|
||||
// Log this at a higher level so admins can
|
||||
// gauge how much spam is being sent to them.
|
||||
//
|
||||
// TODO: add Prometheus metrics for this.
|
||||
log.Infof(ctx, "status %s looked like spam (%v); dropping it",
|
||||
ap.GetJSONLDId(statusable), err,
|
||||
)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// A real error has occurred.
|
||||
return gtserror.Newf("error checking relevancy/spam: %w", err)
|
||||
}
|
||||
|
||||
// If we do have a forward, we should ignore the content
|
||||
|
|
|
|||
572
internal/federation/federatingdb/interactionrequest.go
Normal file
572
internal/federation/federatingdb/interactionrequest.go
Normal file
|
|
@ -0,0 +1,572 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package federatingdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/messages"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
/*
|
||||
The code in this file handles the three types of "polite"
|
||||
interaction requests currently recognized by GoToSocial:
|
||||
LikeRequest, ReplyRequest, and AnnounceRequest.
|
||||
|
||||
A request looks a bit like this, note the requested
|
||||
interaction itself is nested in the "instrument" property:
|
||||
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns"
|
||||
],
|
||||
"type": "LikeRequest",
|
||||
"id": "https://example.com/users/bob/interaction_requests/likes/12345",
|
||||
"actor": "https://example.com/users/bob",
|
||||
"object": "https://example.com/users/alice/statuses/1",
|
||||
"to": "https://example.com/users/alice",
|
||||
"instrument": {
|
||||
"type": "Like",
|
||||
"id": "https://example.com/users/bob/likes/12345",
|
||||
"object": "https://example.com/users/alice/statuses/1",
|
||||
"attributedTo": "https://example.com/users/bob",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
"https://example.com/users/alice"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Because each of the interaction types are a bit different,
|
||||
they're unfortunately also parsed and stored differently:
|
||||
LikeRequests have the Like checked first, here, against
|
||||
the interaction policy of the target status, whereas
|
||||
AnnounceRequests and ReplyRequests have the interaction
|
||||
checked against the interaction policy of the target
|
||||
status asynchronously, in the FromFediAPI processor.
|
||||
|
||||
It may be possible to dick about with the logic a bit and
|
||||
shuffle the checks all here, or all in the processor, but
|
||||
that's a job for future refactoring by future tobi/kimbe.
|
||||
*/
|
||||
|
||||
// partialInteractionRequest represents a
|
||||
// partially-parsed interaction request
|
||||
// returned from the util function parseInteractionReq.
|
||||
type partialInteractionRequest struct {
|
||||
intRequestURI string
|
||||
requesting *gtsmodel.Account
|
||||
receiving *gtsmodel.Account
|
||||
object *gtsmodel.Status
|
||||
instrument vocab.Type
|
||||
}
|
||||
|
||||
// parseIntReq does some first-pass parsing
|
||||
// of the given InteractionRequestable (LikeRequest,
|
||||
// ReplyRequest, AnnounceRequest), checking stuff like:
|
||||
//
|
||||
// - interaction request has a single object
|
||||
// - interaction request object is a status
|
||||
// - object status belongs to receiving account
|
||||
// - interaction request has a single instrument
|
||||
//
|
||||
// It returns a partialInteractionRequest struct,
|
||||
// or an error if something goes wrong.
|
||||
func (f *DB) parseInteractionRequest(ctx context.Context, intRequest ap.InteractionRequestable) (*partialInteractionRequest, error) {
|
||||
|
||||
// Get and stringify the ID/URI of interaction request once,
|
||||
// and mark this particular activity as handled in ID cache.
|
||||
intRequestURI := ap.GetJSONLDId(intRequest).String()
|
||||
f.activityIDs.Set(intRequestURI, struct{}{})
|
||||
|
||||
// Extract relevant values from passed ctx.
|
||||
activityContext := getActivityContext(ctx)
|
||||
if activityContext.internal {
|
||||
// Already processed.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
requesting := activityContext.requestingAcct
|
||||
receiving := activityContext.receivingAcct
|
||||
|
||||
if requesting.IsMoving() {
|
||||
// A Moving account
|
||||
// can't do this.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if receiving.IsMoving() {
|
||||
// Moving accounts can't
|
||||
// do anything with interaction
|
||||
// requests, so ignore it.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Make sure we have a single
|
||||
// object of the interaction request.
|
||||
objectIRIs := ap.GetObjectIRIs(intRequest)
|
||||
if l := len(objectIRIs); l != 1 {
|
||||
return nil, gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"invalid object len %d, wanted 1", l,
|
||||
)
|
||||
}
|
||||
|
||||
// Extract the status URI str.
|
||||
statusIRI := objectIRIs[0]
|
||||
statusIRIStr := statusIRI.String()
|
||||
|
||||
// Fetch status by given URI from the database.
|
||||
status, err := f.state.DB.GetStatusByURI(ctx, statusIRIStr)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return nil, gtserror.Newf("db error getting object status %s: %w", statusIRIStr, err)
|
||||
}
|
||||
|
||||
// Ensure received by correct account.
|
||||
if status.AccountID != receiving.ID {
|
||||
return nil, gtserror.NewfWithCode(
|
||||
http.StatusForbidden,
|
||||
"receiver %s is not owner of interaction-requested status",
|
||||
receiving.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure we have the expected one instrument.
|
||||
instruments := ap.ExtractInstruments(intRequest)
|
||||
if l := len(instruments); l != 1 {
|
||||
return nil, gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"invalid instrument len %d, wanted 1", l,
|
||||
)
|
||||
}
|
||||
|
||||
// Instrument should be a
|
||||
// type and not just an IRI.
|
||||
instrument := instruments[0].GetType()
|
||||
if instrument == nil {
|
||||
return nil, gtserror.NewWithCode(
|
||||
http.StatusBadRequest,
|
||||
"instrument was not vocab.Type",
|
||||
)
|
||||
}
|
||||
|
||||
// Check the instrument is an approveable type.
|
||||
approvable, ok := instrument.(ap.WithApprovedBy)
|
||||
if !ok {
|
||||
return nil, gtserror.NewWithCode(
|
||||
http.StatusBadRequest,
|
||||
"instrument was not Approvable",
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure that `approvedBy` isn't already set.
|
||||
if u := ap.GetApprovedBy(approvable); u != nil {
|
||||
return nil, gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"instrument claims to already be approvedBy %s",
|
||||
u.String(),
|
||||
)
|
||||
}
|
||||
|
||||
return &partialInteractionRequest{
|
||||
intRequestURI: intRequestURI,
|
||||
requesting: requesting,
|
||||
receiving: receiving,
|
||||
object: status,
|
||||
instrument: instrument,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *DB) LikeRequest(ctx context.Context, likeReq vocab.GoToSocialLikeRequest) error {
|
||||
log.DebugKV(ctx, "LikeRequest", serialize{likeReq})
|
||||
|
||||
// Parse out base level interaction request information.
|
||||
partial, err := f.parseInteractionRequest(ctx, likeReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the instrument vocab.Type is Likeable.
|
||||
likeable, ok := ap.ToLikeable(partial.instrument)
|
||||
if !ok {
|
||||
return gtserror.NewWithCode(
|
||||
http.StatusBadRequest,
|
||||
"could not parse instrument to Likeable",
|
||||
)
|
||||
}
|
||||
|
||||
// Convert received AS like type to internal fave model.
|
||||
fave, err := f.converter.ASLikeToFave(ctx, likeable)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting from AS type: %w", err)
|
||||
return gtserror.WrapWithCode(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Ensure fave enacted by correct account.
|
||||
if fave.AccountID != partial.requesting.ID {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusForbidden,
|
||||
"requester %s is not expected actor %s",
|
||||
partial.requesting.URI, fave.Account.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure fave received by correct account.
|
||||
if fave.TargetAccountID != partial.receiving.ID {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusForbidden,
|
||||
"receiver %s is not expected %s",
|
||||
partial.receiving.URI, fave.TargetAccount.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure this is a valid Like target for requester.
|
||||
policyResult, err := f.intFilter.StatusLikeable(ctx,
|
||||
partial.requesting,
|
||||
fave.Status,
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf(
|
||||
"error seeing if status %s is likeable: %w",
|
||||
fave.Status.URI, err,
|
||||
)
|
||||
} else if policyResult.Forbidden() {
|
||||
return gtserror.NewWithCode(
|
||||
http.StatusForbidden,
|
||||
"requester does not have permission to Like status",
|
||||
)
|
||||
}
|
||||
|
||||
// Policy result is either automatic or manual
|
||||
// approval, so store the interaction request.
|
||||
intReq := >smodel.InteractionRequest{
|
||||
ID: id.NewULID(),
|
||||
TargetStatusID: fave.StatusID,
|
||||
TargetStatus: fave.Status,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionRequestURI: partial.intRequestURI,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(true),
|
||||
Like: fave,
|
||||
}
|
||||
switch err := f.state.DB.PutInteractionRequest(ctx, intReq); {
|
||||
case err == nil:
|
||||
// No problem.
|
||||
|
||||
case errors.Is(err, db.ErrAlreadyExists):
|
||||
// Already processed this, race condition? Just warn + return.
|
||||
log.Warnf(ctx, "received duplicate interaction request: %s", partial.intRequestURI)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// Proper DB error.
|
||||
return gtserror.Newf(
|
||||
"db error storing interaction request %s",
|
||||
partial.intRequestURI,
|
||||
)
|
||||
}
|
||||
|
||||
// Int req is now stored.
|
||||
//
|
||||
// Set some fields on the
|
||||
// pending fave and store it.
|
||||
fave.ID = id.NewULID()
|
||||
fave.PendingApproval = util.Ptr(true)
|
||||
fave.PreApproved = policyResult.AutomaticApproval()
|
||||
if err := f.state.DB.PutStatusFave(ctx, fave); err != nil {
|
||||
if errors.Is(err, db.ErrAlreadyExists) {
|
||||
// The fave already exists in the
|
||||
// database, which means we've already
|
||||
// handled side effects. We can just
|
||||
// return nil here and be done with it.
|
||||
return nil
|
||||
}
|
||||
|
||||
return gtserror.Newf("error inserting %s into db: %w", fave.URI, err)
|
||||
}
|
||||
|
||||
// Further processing will be carried out
|
||||
// asynchronously, and our caller will return 202 Accepted.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APActivityType: ap.ActivityCreate,
|
||||
APObjectType: ap.ActivityLikeRequest,
|
||||
GTSModel: intReq,
|
||||
Receiving: partial.receiving,
|
||||
Requesting: partial.requesting,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *DB) ReplyRequest(ctx context.Context, replyReq vocab.GoToSocialReplyRequest) error {
|
||||
log.DebugKV(ctx, "ReplyRequest", serialize{replyReq})
|
||||
|
||||
// Parse out base level interaction request information.
|
||||
partial, err := f.parseInteractionRequest(ctx, replyReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the instrument vocab.Type is Statusable.
|
||||
statusable, ok := ap.ToStatusable(partial.instrument)
|
||||
if !ok {
|
||||
return gtserror.NewWithCode(
|
||||
http.StatusBadRequest,
|
||||
"could not parse instrument to Statusable",
|
||||
)
|
||||
}
|
||||
|
||||
// Check for spam / relevance.
|
||||
ok, err = f.statusableOK(
|
||||
ctx,
|
||||
partial.receiving,
|
||||
partial.requesting,
|
||||
statusable,
|
||||
)
|
||||
if err != nil {
|
||||
// Error already
|
||||
// wrapped.
|
||||
return err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// Not relevant / spam.
|
||||
// Already logged.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Statusable must reply to something.
|
||||
inReplyToURIs := ap.GetInReplyTo(statusable)
|
||||
if l := len(inReplyToURIs); l != 1 {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"expected inReplyTo length 1, got %d", l,
|
||||
)
|
||||
}
|
||||
inReplyToURI := inReplyToURIs[0]
|
||||
inReplyToURIStr := inReplyToURI.String()
|
||||
|
||||
// Make sure we have the status this interaction reply encompasses.
|
||||
inReplyTo, err := f.state.DB.GetStatusByURI(ctx, inReplyToURIStr)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return gtserror.Newf("db error getting inReplyTo status %s: %w", inReplyToURIStr, err)
|
||||
}
|
||||
|
||||
// Check status exists.
|
||||
if inReplyTo == nil {
|
||||
log.Warnf(ctx, "received ReplyRequest for non-existent status: %s", inReplyToURIStr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Make sure the parent status is owned by receiver.
|
||||
if inReplyTo.AccountURI != partial.receiving.URI {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"inReplyTo status %s not owned by receiving account %s",
|
||||
inReplyToURIStr, partial.receiving.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Extract the attributed to (i.e. author) URI of status.
|
||||
attributedToURI, err := ap.ExtractAttributedToURI(statusable)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("invalid status attributedTo value: %w", err)
|
||||
return gtserror.WrapWithCode(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Ensure status author is account of requester.
|
||||
attributedToURIStr := attributedToURI.String()
|
||||
if attributedToURIStr != partial.requesting.URI {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"status attributedTo %s not requesting account %s",
|
||||
inReplyToURIStr, partial.requesting.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Create a pending interaction request in the database.
|
||||
// This request will be handled further by the processor.
|
||||
intReq := >smodel.InteractionRequest{
|
||||
ID: id.NewULID(),
|
||||
TargetStatusID: inReplyTo.ID,
|
||||
TargetStatus: inReplyTo,
|
||||
TargetAccountID: inReplyTo.AccountID,
|
||||
TargetAccount: inReplyTo.Account,
|
||||
InteractingAccountID: partial.requesting.ID,
|
||||
InteractingAccount: partial.requesting,
|
||||
InteractionRequestURI: partial.intRequestURI,
|
||||
InteractionURI: ap.GetJSONLDId(statusable).String(),
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(true),
|
||||
Reply: nil, // Not settable yet.
|
||||
}
|
||||
switch err := f.state.DB.PutInteractionRequest(ctx, intReq); {
|
||||
case err == nil:
|
||||
// No problem.
|
||||
|
||||
case errors.Is(err, db.ErrAlreadyExists):
|
||||
// Already processed this, race condition? Just warn + return.
|
||||
log.Warnf(ctx, "received duplicate interaction request: %s", partial.intRequestURI)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// Proper DB error.
|
||||
return gtserror.Newf(
|
||||
"db error storing interaction request %s",
|
||||
partial.intRequestURI,
|
||||
)
|
||||
}
|
||||
|
||||
// Further processing will be carried out
|
||||
// asynchronously, return 202 Accepted.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APActivityType: ap.ActivityCreate,
|
||||
APObjectType: ap.ActivityReplyRequest,
|
||||
GTSModel: intReq,
|
||||
APObject: statusable,
|
||||
Receiving: partial.receiving,
|
||||
Requesting: partial.requesting,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *DB) AnnounceRequest(ctx context.Context, announceReq vocab.GoToSocialAnnounceRequest) error {
|
||||
log.DebugKV(ctx, "AnnounceRequest", serialize{announceReq})
|
||||
|
||||
// Parse out base level interaction request information.
|
||||
partial, err := f.parseInteractionRequest(ctx, announceReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the instrument vocab.Type is Announceable.
|
||||
announceable, ok := ap.ToAnnounceable(partial.instrument)
|
||||
if !ok {
|
||||
return gtserror.NewWithCode(
|
||||
http.StatusBadRequest,
|
||||
"could not parse instrument to Announceable",
|
||||
)
|
||||
}
|
||||
|
||||
// Convert received AS Announce type to internal boost wrapper model.
|
||||
boost, new, err := f.converter.ASAnnounceToStatus(ctx, announceable)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting from AS type: %w", err)
|
||||
return gtserror.WrapWithCode(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
if !new {
|
||||
// We already have this announce, just return.
|
||||
log.Warnf(ctx, "received AnnounceRequest for existing announce: %s", boost.URI)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fetch origin status that this boost is targetting from database.
|
||||
targetStatus, err := f.state.DB.GetStatusByURI(ctx, boost.BoostOfURI)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return gtserror.Newf(
|
||||
"db error getting announce object %s: %w",
|
||||
boost.BoostOfURI, err,
|
||||
)
|
||||
}
|
||||
|
||||
if targetStatus == nil {
|
||||
// Status doesn't seem to exist, just drop this AnnounceRequest.
|
||||
log.Warnf(ctx, "received AnnounceRequest for non-existent status %s", boost.BoostOfURI)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure target status is owned by receiving account.
|
||||
if targetStatus.AccountID != partial.receiving.ID {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusBadRequest,
|
||||
"announce object %s not owned by receiving account %s",
|
||||
boost.BoostOfURI, partial.receiving.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure announce enacted by correct account.
|
||||
if boost.AccountID != partial.requesting.ID {
|
||||
return gtserror.NewfWithCode(
|
||||
http.StatusForbidden,
|
||||
"requester %s is not expected actor %s",
|
||||
partial.requesting.URI, boost.Account.URI,
|
||||
)
|
||||
}
|
||||
|
||||
// Create a pending interaction request in the database.
|
||||
// This request will be handled further by the processor.
|
||||
intReq := >smodel.InteractionRequest{
|
||||
ID: id.NewULID(),
|
||||
TargetStatusID: targetStatus.ID,
|
||||
TargetStatus: targetStatus,
|
||||
TargetAccountID: targetStatus.AccountID,
|
||||
TargetAccount: targetStatus.Account,
|
||||
InteractingAccountID: boost.AccountID,
|
||||
InteractingAccount: boost.Account,
|
||||
InteractionRequestURI: partial.intRequestURI,
|
||||
InteractionURI: boost.URI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Polite: util.Ptr(true),
|
||||
Announce: boost,
|
||||
}
|
||||
switch err := f.state.DB.PutInteractionRequest(ctx, intReq); {
|
||||
case err == nil:
|
||||
// No problem.
|
||||
|
||||
case errors.Is(err, db.ErrAlreadyExists):
|
||||
// Already processed this, race condition? Just warn + return.
|
||||
log.Warnf(ctx, "received duplicate interaction request: %s", partial.intRequestURI)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// Proper DB error.
|
||||
return gtserror.Newf(
|
||||
"db error storing interaction request %s",
|
||||
partial.intRequestURI,
|
||||
)
|
||||
}
|
||||
|
||||
// Further processing will be carried out
|
||||
// asynchronously, return 202 Accepted.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APActivityType: ap.ActivityCreate,
|
||||
APObjectType: ap.ActivityAnnounceRequest,
|
||||
GTSModel: intReq,
|
||||
Receiving: partial.receiving,
|
||||
Requesting: partial.requesting,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
289
internal/federation/federatingdb/interactionrequest_test.go
Normal file
289
internal/federation/federatingdb/interactionrequest_test.go
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package federatingdb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.superseriousbusiness.org/activity/streams"
|
||||
"code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type InteractionRequestTestSuite struct {
|
||||
FederatingDBTestSuite
|
||||
}
|
||||
|
||||
func (suite *InteractionRequestTestSuite) intReq(
|
||||
receiving *gtsmodel.Account,
|
||||
requesting *gtsmodel.Account,
|
||||
jsonStr string,
|
||||
dbF func(ctx context.Context, req vocab.Type) error,
|
||||
) error {
|
||||
ctx := createTestContext(suite.T(), receiving, requesting)
|
||||
|
||||
raw := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(jsonStr), &raw); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
t, err := streams.ToType(ctx, raw)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
return dbF(ctx, t)
|
||||
}
|
||||
|
||||
func (suite *InteractionRequestTestSuite) TestReplyRequest() {
|
||||
var (
|
||||
ctx = suite.T().Context()
|
||||
receiving = suite.testAccounts["admin_account"]
|
||||
requesting = suite.testAccounts["remote_account_1"]
|
||||
testStatus = suite.testStatuses["admin_account_status_1"]
|
||||
intReqURI = "http://fossbros-anonymous.io/requests/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
intURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
jsonStr = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns"
|
||||
],
|
||||
"type": "ReplyRequest",
|
||||
"id": "` + intReqURI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"to": "` + receiving.URI + `",
|
||||
"instrument": {
|
||||
"attributedTo": "` + requesting.URI + `",
|
||||
"cc": "` + requesting.FollowersURI + `",
|
||||
"content": "\u003cp\u003ethis is a reply!\u003c/p\u003e",
|
||||
"id": "` + intURI + `",
|
||||
"inReplyTo": "` + testStatus.URI + `",
|
||||
"tag": {
|
||||
"href": "` + receiving.URI + `",
|
||||
"name": "@` + receiving.Username + `@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}
|
||||
}`
|
||||
)
|
||||
|
||||
suite.T().Logf("testing reply request:\n\n%s", jsonStr)
|
||||
|
||||
// Call the federatingDB function.
|
||||
err := suite.intReq(
|
||||
receiving,
|
||||
requesting,
|
||||
jsonStr,
|
||||
func(ctx context.Context, req vocab.Type) error {
|
||||
replyReq := req.(vocab.GoToSocialReplyRequest)
|
||||
return suite.federatingDB.ReplyRequest(ctx, replyReq)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// There should be an interaction request in the DB now.
|
||||
var intReq *gtsmodel.InteractionRequest
|
||||
if !testrig.WaitFor(func() bool {
|
||||
intReq, err = suite.state.DB.GetInteractionRequestByInteractionURI(ctx, intURI)
|
||||
return err == nil && intReq != nil
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for int req to appear in the db")
|
||||
}
|
||||
suite.Equal(testStatus.ID, intReq.TargetStatusID)
|
||||
suite.Equal(receiving.ID, intReq.TargetAccountID)
|
||||
suite.Equal(requesting.ID, intReq.InteractingAccountID)
|
||||
suite.Equal(intReqURI, intReq.InteractionRequestURI)
|
||||
suite.Equal(intURI, intReq.InteractionURI)
|
||||
suite.Equal(gtsmodel.InteractionReply, intReq.InteractionType)
|
||||
|
||||
// Should be a message heading to the processor.
|
||||
msg, _ := suite.getFederatorMsg(5 * time.Second)
|
||||
suite.Equal(ap.ActivityCreate, msg.APActivityType)
|
||||
suite.Equal(ap.ActivityReplyRequest, msg.APObjectType)
|
||||
suite.NotNil(msg.GTSModel)
|
||||
suite.NotNil(msg.APObject)
|
||||
suite.NotNil(msg.Receiving)
|
||||
suite.NotNil(msg.Requesting)
|
||||
}
|
||||
|
||||
func (suite *InteractionRequestTestSuite) TestLikeRequest() {
|
||||
var (
|
||||
ctx = suite.T().Context()
|
||||
receiving = suite.testAccounts["admin_account"]
|
||||
requesting = suite.testAccounts["remote_account_1"]
|
||||
testStatus = suite.testStatuses["admin_account_status_1"]
|
||||
intReqURI = "http://fossbros-anonymous.io/requests/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
intURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
jsonStr = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns"
|
||||
],
|
||||
"type": "LikeRequest",
|
||||
"id": "` + intReqURI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"to": "` + receiving.URI + `",
|
||||
"instrument": {
|
||||
"id": "` + intURI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"to": "` + receiving.URI + `",
|
||||
"type": "Like"
|
||||
}
|
||||
}`
|
||||
)
|
||||
|
||||
suite.T().Logf("testing like request:\n\n%s", jsonStr)
|
||||
|
||||
// Call the federatingDB function.
|
||||
err := suite.intReq(
|
||||
receiving,
|
||||
requesting,
|
||||
jsonStr,
|
||||
func(ctx context.Context, req vocab.Type) error {
|
||||
likeReq := req.(vocab.GoToSocialLikeRequest)
|
||||
return suite.federatingDB.LikeRequest(ctx, likeReq)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// There should be an interaction request in the DB now.
|
||||
var intReq *gtsmodel.InteractionRequest
|
||||
if !testrig.WaitFor(func() bool {
|
||||
intReq, err = suite.state.DB.GetInteractionRequestByInteractionURI(ctx, intURI)
|
||||
return err == nil && intReq != nil
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for int req to appear in the db")
|
||||
}
|
||||
suite.Equal(testStatus.ID, intReq.TargetStatusID)
|
||||
suite.Equal(receiving.ID, intReq.TargetAccountID)
|
||||
suite.Equal(requesting.ID, intReq.InteractingAccountID)
|
||||
suite.Equal(intReqURI, intReq.InteractionRequestURI)
|
||||
suite.Equal(intURI, intReq.InteractionURI)
|
||||
suite.Equal(gtsmodel.InteractionLike, intReq.InteractionType)
|
||||
|
||||
// The like should be in the DB now (unapproved).
|
||||
var statusFave *gtsmodel.StatusFave
|
||||
if !testrig.WaitFor(func() bool {
|
||||
statusFave, err = suite.state.DB.GetStatusFaveByURI(ctx, intURI)
|
||||
return err == nil && intReq != nil
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for fave to appear in the db")
|
||||
}
|
||||
suite.Equal(requesting.ID, statusFave.AccountID)
|
||||
suite.Equal(receiving.ID, statusFave.TargetAccountID)
|
||||
suite.Equal(testStatus.ID, statusFave.StatusID)
|
||||
suite.Equal(intURI, statusFave.URI)
|
||||
suite.True(*statusFave.PendingApproval)
|
||||
suite.Empty(statusFave.ApprovedByURI)
|
||||
|
||||
// Should be a message heading to the processor.
|
||||
msg, _ := suite.getFederatorMsg(5 * time.Second)
|
||||
suite.Equal(ap.ActivityCreate, msg.APActivityType)
|
||||
suite.Equal(ap.ActivityLikeRequest, msg.APObjectType)
|
||||
suite.NotNil(msg.GTSModel)
|
||||
suite.NotNil(msg.Receiving)
|
||||
suite.NotNil(msg.Requesting)
|
||||
}
|
||||
|
||||
func (suite *InteractionRequestTestSuite) TestAnnounceRequest() {
|
||||
var (
|
||||
ctx = suite.T().Context()
|
||||
receiving = suite.testAccounts["admin_account"]
|
||||
requesting = suite.testAccounts["remote_account_1"]
|
||||
testStatus = suite.testStatuses["admin_account_status_1"]
|
||||
intReqURI = "http://fossbros-anonymous.io/requests/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
intURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
jsonStr = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns"
|
||||
],
|
||||
"type": "AnnounceRequest",
|
||||
"id": "` + intReqURI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"to": "` + receiving.URI + `",
|
||||
"instrument": {
|
||||
"id": "` + intURI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"to": "` + requesting.FollowersURI + `",
|
||||
"cc": "` + receiving.URI + `",
|
||||
"type": "Announce"
|
||||
}
|
||||
}`
|
||||
)
|
||||
|
||||
suite.T().Logf("testing announce request:\n\n%s", jsonStr)
|
||||
|
||||
// Call the federatingDB function.
|
||||
err := suite.intReq(
|
||||
receiving,
|
||||
requesting,
|
||||
jsonStr,
|
||||
func(ctx context.Context, req vocab.Type) error {
|
||||
announceReq := req.(vocab.GoToSocialAnnounceRequest)
|
||||
return suite.federatingDB.AnnounceRequest(ctx, announceReq)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// There should be an interaction request in the DB now.
|
||||
var intReq *gtsmodel.InteractionRequest
|
||||
if !testrig.WaitFor(func() bool {
|
||||
intReq, err = suite.state.DB.GetInteractionRequestByInteractionURI(ctx, intURI)
|
||||
return err == nil && intReq != nil
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for int req to appear in the db")
|
||||
}
|
||||
suite.Equal(testStatus.ID, intReq.TargetStatusID)
|
||||
suite.Equal(receiving.ID, intReq.TargetAccountID)
|
||||
suite.Equal(requesting.ID, intReq.InteractingAccountID)
|
||||
suite.Equal(intReqURI, intReq.InteractionRequestURI)
|
||||
suite.Equal(intURI, intReq.InteractionURI)
|
||||
suite.Equal(gtsmodel.InteractionAnnounce, intReq.InteractionType)
|
||||
|
||||
// Should be a message heading to the processor.
|
||||
msg, _ := suite.getFederatorMsg(5 * time.Second)
|
||||
suite.Equal(ap.ActivityCreate, msg.APActivityType)
|
||||
suite.Equal(ap.ActivityAnnounceRequest, msg.APObjectType)
|
||||
suite.NotNil(msg.GTSModel)
|
||||
suite.NotNil(msg.Receiving)
|
||||
suite.NotNil(msg.Requesting)
|
||||
}
|
||||
|
||||
func TestInteractionRequestTestSuite(t *testing.T) {
|
||||
suite.Run(t, &InteractionRequestTestSuite{})
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ func (f *DB) Like(ctx context.Context, likeable vocab.ActivityStreamsLike) error
|
|||
requesting := activityContext.requestingAcct
|
||||
receiving := activityContext.receivingAcct
|
||||
|
||||
if receiving.IsMoving() {
|
||||
if requesting.IsMoving() {
|
||||
// A Moving account
|
||||
// can't do this.
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/messages"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/uris"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (f *DB) Reject(ctx context.Context, reject vocab.ActivityStreamsReject) error {
|
||||
|
|
@ -305,21 +306,24 @@ func (f *DB) rejectStatusIRI(
|
|||
InteractingAccountID: receivingAcct.ID,
|
||||
InteractingAccount: receivingAcct,
|
||||
InteractionURI: status.URI,
|
||||
URI: activityID,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: activityID,
|
||||
RejectedAt: time.Now(),
|
||||
}
|
||||
|
||||
if apObjectType == ap.ObjectNote {
|
||||
// Reply.
|
||||
req.InteractionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.ReplyRequestSuffix)
|
||||
req.InteractionType = gtsmodel.InteractionReply
|
||||
req.StatusID = status.InReplyToID
|
||||
req.Status = status.InReplyTo
|
||||
req.TargetStatusID = status.InReplyToID
|
||||
req.TargetStatus = status.InReplyTo
|
||||
req.Reply = status
|
||||
} else {
|
||||
// Announce.
|
||||
req.InteractionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.AnnounceRequestSuffix)
|
||||
req.InteractionType = gtsmodel.InteractionAnnounce
|
||||
req.StatusID = status.BoostOfID
|
||||
req.Status = status.BoostOf
|
||||
req.TargetStatusID = status.BoostOfID
|
||||
req.TargetStatus = status.BoostOf
|
||||
req.Announce = status
|
||||
}
|
||||
|
||||
|
|
@ -331,8 +335,8 @@ func (f *DB) rejectStatusIRI(
|
|||
case req.IsRejected():
|
||||
// Interaction has already been rejected. Just
|
||||
// update to this Reject URI and then return early.
|
||||
req.URI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req, "uri"); err != nil {
|
||||
req.ResponseURI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req, "response_uri"); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
|
@ -343,11 +347,11 @@ func (f *DB) rejectStatusIRI(
|
|||
// Rejected, even if previously Accepted.
|
||||
req.AcceptedAt = time.Time{}
|
||||
req.RejectedAt = time.Now()
|
||||
req.URI = activityID
|
||||
req.ResponseURI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req,
|
||||
"accepted_at",
|
||||
"rejected_at",
|
||||
"uri",
|
||||
"response_uri",
|
||||
); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return gtserror.NewErrorInternalError(err)
|
||||
|
|
@ -430,16 +434,18 @@ func (f *DB) rejectLikeIRI(
|
|||
// No interaction request existed yet for this
|
||||
// fave, create a pre-rejected request now.
|
||||
req = >smodel.InteractionRequest{
|
||||
ID: id.NewULID(),
|
||||
TargetAccountID: requestingAcct.ID,
|
||||
TargetAccount: requestingAcct,
|
||||
InteractingAccountID: receivingAcct.ID,
|
||||
InteractingAccount: receivingAcct,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Like: fave,
|
||||
URI: activityID,
|
||||
RejectedAt: time.Now(),
|
||||
ID: id.NewULID(),
|
||||
TargetAccountID: requestingAcct.ID,
|
||||
TargetAccount: requestingAcct,
|
||||
InteractingAccountID: receivingAcct.ID,
|
||||
InteractingAccount: receivingAcct,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(fave.URI, gtsmodel.LikeRequestSuffix),
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
Like: fave,
|
||||
ResponseURI: activityID,
|
||||
RejectedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := f.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
|
|
@ -450,8 +456,8 @@ func (f *DB) rejectLikeIRI(
|
|||
case req.IsRejected():
|
||||
// Interaction has already been rejected. Just
|
||||
// update to this Reject URI and then return early.
|
||||
req.URI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req, "uri"); err != nil {
|
||||
req.ResponseURI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req, "response_uri"); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
|
@ -462,11 +468,11 @@ func (f *DB) rejectLikeIRI(
|
|||
// Rejected, even if previously Accepted.
|
||||
req.AcceptedAt = time.Time{}
|
||||
req.RejectedAt = time.Now()
|
||||
req.URI = activityID
|
||||
req.ResponseURI = activityID
|
||||
if err := f.state.DB.UpdateInteractionRequest(ctx, req,
|
||||
"accepted_at",
|
||||
"rejected_at",
|
||||
"uri",
|
||||
"response_uri",
|
||||
); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return gtserror.NewErrorInternalError(err)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/config"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
|
|
@ -110,11 +111,9 @@ func (f *DB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL, err error
|
|||
// based on actor (i.e. followER not the followEE).
|
||||
if uri := ap.GetActorIRIs(follow); len(uri) == 1 {
|
||||
if actorAccount, err := f.state.DB.GetAccountByURI(ctx, uri[0].String()); err == nil {
|
||||
newID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return url.Parse(uris.GenerateURIForFollow(actorAccount.Username, newID))
|
||||
newID := id.NewRandomULID()
|
||||
uri := uris.GenerateURIForFollow(actorAccount.Username, newID)
|
||||
return url.Parse(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -234,3 +233,53 @@ func (s serialize) String() string {
|
|||
|
||||
return byteutil.B2S(b)
|
||||
}
|
||||
|
||||
// statusableOK is a util function to check if
|
||||
// the given statusable is "ok" in terms of being
|
||||
// relevant to the receiver, and passing spam checks.
|
||||
func (f *DB) statusableOK(
|
||||
ctx context.Context,
|
||||
receiver *gtsmodel.Account,
|
||||
requester *gtsmodel.Account,
|
||||
statusable ap.Statusable,
|
||||
) (bool, error) {
|
||||
// Check whether this status is both
|
||||
// relevant, and doesn't look like spam.
|
||||
err := f.spamFilter.StatusableOK(ctx,
|
||||
receiver,
|
||||
requester,
|
||||
statusable,
|
||||
)
|
||||
|
||||
switch {
|
||||
case err == nil:
|
||||
// No problem!
|
||||
return true, nil
|
||||
|
||||
case gtserror.IsNotRelevant(err):
|
||||
// This case is quite common if a remote (Mastodon)
|
||||
// instance forwards a message to us which is a reply
|
||||
// from someone else to a status we've also replied to.
|
||||
//
|
||||
// It does this to try to ensure thread completion, but
|
||||
// we have our own thread fetching mechanism anyway.
|
||||
log.Debugf(ctx, "status %s is not relevant to receiver (%v); dropping it",
|
||||
ap.GetJSONLDId(statusable), err,
|
||||
)
|
||||
return false, nil
|
||||
|
||||
case gtserror.IsSpam(err):
|
||||
// Log this at a higher level so admins can
|
||||
// gauge how much spam is being sent to them.
|
||||
//
|
||||
// TODO: add Prometheus metrics for this.
|
||||
log.Infof(ctx, "status %s looked like spam (%v); dropping it",
|
||||
ap.GetJSONLDId(statusable), err,
|
||||
)
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
// A real error has occurred.
|
||||
return false, gtserror.Newf("error checking relevancy/spam: %w", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ func NewFederator(
|
|||
federatingDB.Announce,
|
||||
federatingDB.Move,
|
||||
federatingDB.Flag,
|
||||
federatingDB.LikeRequest,
|
||||
federatingDB.ReplyRequest,
|
||||
federatingDB.AnnounceRequest,
|
||||
},
|
||||
}
|
||||
actor := newFederatingActor(f, f, federatingDB, clock)
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ func SetUnretrievable(err error) error {
|
|||
return errors.WithValue(err, unrtrvableKey, struct{}{})
|
||||
}
|
||||
|
||||
// NotPermitted indicates that some call failed due to failed permission
|
||||
// IsNotPermitted indicates that some call failed due to failed permission
|
||||
// or acceptibility checks. For example an attempt to dereference remote
|
||||
// status in which the status author does not have permission to reply
|
||||
// to the status it is intended to be replying to.
|
||||
func NotPermitted(err error) bool {
|
||||
func IsNotPermitted(err error) bool {
|
||||
_, ok := errors.Value(err, notPermittedKey).(struct{})
|
||||
return ok
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ package gtsmodel
|
|||
import "time"
|
||||
|
||||
// Like / Reply / Announce
|
||||
type InteractionType int
|
||||
type InteractionType enumType
|
||||
|
||||
const (
|
||||
// WARNING: DO NOT CHANGE THE ORDER OF THESE,
|
||||
|
|
@ -29,11 +29,34 @@ const (
|
|||
// If you need to add new interaction types,
|
||||
// add them *to the end* of the list.
|
||||
|
||||
InteractionLike InteractionType = iota
|
||||
InteractionReply
|
||||
InteractionAnnounce
|
||||
InteractionLike InteractionType = 0
|
||||
InteractionReply InteractionType = 1
|
||||
InteractionAnnounce InteractionType = 2
|
||||
)
|
||||
|
||||
const (
|
||||
// Suffix to append to the URI of
|
||||
// impolite Likes to mock a LikeRequest.
|
||||
LikeRequestSuffix = "#LikeRequest"
|
||||
|
||||
// Suffix to append to the URI of
|
||||
// impolite replies to mock a ReplyRequest.
|
||||
ReplyRequestSuffix = "#ReplyRequest"
|
||||
|
||||
// Suffix to append to the URI of impolite
|
||||
// Announces to mock an AnnounceRequest.
|
||||
AnnounceRequestSuffix = "#AnnounceRequest"
|
||||
)
|
||||
|
||||
// A useless function that appends two strings, this exists largely
|
||||
// to indicate where a request URI is being generated as forward compatible
|
||||
// with our planned polite request flow fully introduced in v0.21.0.
|
||||
//
|
||||
// TODO: remove this in v0.21.0. everything the linter complains about after removing this, needs updating.
|
||||
func ForwardCompatibleInteractionRequestURI(interactionURI string, suffix string) string {
|
||||
return interactionURI + suffix
|
||||
}
|
||||
|
||||
// Stringifies this InteractionType in a
|
||||
// manner suitable for serving via the API.
|
||||
func (i InteractionType) String() string {
|
||||
|
|
@ -52,30 +75,80 @@ func (i InteractionType) String() string {
|
|||
}
|
||||
}
|
||||
|
||||
// InteractionRequest represents one interaction (like, reply, fave)
|
||||
// that is either accepted, rejected, or currently still awaiting
|
||||
// InteractionRequest represents one interaction request
|
||||
// that is either accepted, rejected, or awaiting
|
||||
// acceptance or rejection by the target account.
|
||||
type InteractionRequest struct {
|
||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database
|
||||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created
|
||||
StatusID string `bun:"type:CHAR(26),nullzero,notnull"` // ID of the interaction target status.
|
||||
Status *Status `bun:"-"` // Not stored in DB. Status being interacted with.
|
||||
TargetAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // id of the account being interacted with
|
||||
TargetAccount *Account `bun:"-"` // Not stored in DB. Account being interacted with.
|
||||
InteractingAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // id of the account requesting the interaction.
|
||||
InteractingAccount *Account `bun:"-"` // Not stored in DB. Account corresponding to targetAccountID
|
||||
InteractionURI string `bun:",nullzero,notnull,unique"` // URI of the interacting like, reply, or announce. Unique (only one interaction request allowed per interaction URI).
|
||||
InteractionType InteractionType `bun:",notnull"` // One of Like, Reply, or Announce.
|
||||
Like *StatusFave `bun:"-"` // Not stored in DB. Only set if InteractionType = InteractionLike.
|
||||
Reply *Status `bun:"-"` // Not stored in DB. Only set if InteractionType = InteractionReply.
|
||||
Announce *Status `bun:"-"` // Not stored in DB. Only set if InteractionType = InteractionAnnounce.
|
||||
AcceptedAt time.Time `bun:"type:timestamptz,nullzero"` // If interaction request was accepted, time at which this occurred.
|
||||
RejectedAt time.Time `bun:"type:timestamptz,nullzero"` // If interaction request was rejected, time at which this occurred.
|
||||
|
||||
// ActivityPub URI of the Accept (if accepted) or Reject (if rejected).
|
||||
// ID of this item in the database.
|
||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`
|
||||
|
||||
// ID of the status targeted by the interaction.
|
||||
TargetStatusID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
// Local status corresponding to TargetStatusID.
|
||||
// Column not stored in DB.
|
||||
TargetStatus *Status `bun:"-"`
|
||||
|
||||
// ID of the account being interacted with.
|
||||
TargetAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
// Account corresponding to TargetAccountID.
|
||||
// Column not stored in DB.
|
||||
TargetAccount *Account `bun:"-"`
|
||||
|
||||
// ID of the account doing the interaction request.
|
||||
InteractingAccountID string `bun:"type:CHAR(26),nullzero,notnull"`
|
||||
|
||||
// Account corresponding to InteractingAccountID.
|
||||
// Column not stored in DB.
|
||||
InteractingAccount *Account `bun:"-"`
|
||||
|
||||
// URI of the Request, if this InteractionRequest originated from
|
||||
// a polite Request type (LikeRequest, ReplyRequest, AnnounceRequest, etc.).
|
||||
//
|
||||
// If the interaction request originated from an interaction
|
||||
// (Like, Create (status), Announce, etc.) transmitted impolitely,
|
||||
// this will be set to a mocked URI.
|
||||
InteractionRequestURI string `bun:",nullzero,notnull,unique"`
|
||||
|
||||
// URI of the interaction itself.
|
||||
InteractionURI string `bun:",nullzero,notnull,unique"`
|
||||
|
||||
// Type of interaction being requested.
|
||||
InteractionType InteractionType `bun:",notnull"`
|
||||
|
||||
// True if this interaction request
|
||||
// originated from a polite Request type.
|
||||
Polite *bool `bun:",nullzero,notnull,default:false"`
|
||||
|
||||
// Set if InteractionType = InteractionLike.
|
||||
// Column not stored in DB.
|
||||
Like *StatusFave `bun:"-"`
|
||||
|
||||
// Set if InteractionType = InteractionReply.
|
||||
// Column not stored in DB.
|
||||
Reply *Status `bun:"-"`
|
||||
|
||||
// Set if InteractionType = InteractionAnnounce.
|
||||
// Column not stored in DB.
|
||||
Announce *Status `bun:"-"`
|
||||
|
||||
// If interaction request was accepted, time at which this occurred.
|
||||
AcceptedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
|
||||
// If interaction request was rejected, time at which this occurred.
|
||||
RejectedAt time.Time `bun:"type:timestamptz,nullzero"`
|
||||
|
||||
// URI of the Accept (if accepted) or Reject (if rejected).
|
||||
// Field may be empty if currently neither accepted not rejected, or if
|
||||
// acceptance/rejection was implicit (ie., not resulting from an Activity).
|
||||
URI string `bun:",nullzero,unique"`
|
||||
ResponseURI string `bun:",nullzero,unique"`
|
||||
|
||||
// URI of the Authorization object (if accepted).
|
||||
//
|
||||
// Field will only be set if the interaction has been accepted.
|
||||
AuthorizationURI string `bun:",nullzero,unique"`
|
||||
}
|
||||
|
||||
// IsHandled returns true if interaction
|
||||
|
|
@ -96,6 +169,39 @@ func (ir *InteractionRequest) IsRejected() bool {
|
|||
return !ir.RejectedAt.IsZero()
|
||||
}
|
||||
|
||||
// IsPolite returns true if this interaction request was done
|
||||
// "politely" with a *Request type, or false if it was done
|
||||
// "impolitely" with direct send of a like, reply, or announce.
|
||||
//
|
||||
// The following information is not strictly needed but provides
|
||||
// useful context for why interaction requests are determined to
|
||||
// be either "polite" or "impolite".
|
||||
//
|
||||
// A "polite" interaction request flow indicates that it was
|
||||
// performed with the latest currently accepted manner of doing
|
||||
// things. This manner is different to that initially introduced
|
||||
// by us (GoToSocial) pre-v0.20.0, as it is the result of our
|
||||
// previous design going through many iterations with Mastodon
|
||||
// developers as part of designing their similar quote post flow.
|
||||
//
|
||||
// An "impolite" interaction request flow is that produced either
|
||||
// by an older interaction-policy-AWARE GoToSocial instance, or
|
||||
// by any interaction-policy-UNAWARE server instance.
|
||||
//
|
||||
// Regarding per-version GoToSocial behaviour (summarized by tobi):
|
||||
//
|
||||
// - from v0.19.0 and before, we know about and can respond only to
|
||||
// impolite interactions, and we send out impolite as well
|
||||
//
|
||||
// - from v0.20.0 onwards, we know about and can respond to both
|
||||
// polite / impolite interaction requests, but we still send out impolite
|
||||
//
|
||||
// - from v0.21.0 onwards, we know about and can respond to both
|
||||
// polite and impolite interaction requests, and we send out polite
|
||||
func (ir *InteractionRequest) IsPolite() bool {
|
||||
return ir.Polite != nil && *ir.Polite
|
||||
}
|
||||
|
||||
// Interaction abstractly represents
|
||||
// one interaction with a status, via
|
||||
// liking, replying to, or boosting it.
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ type Status struct {
|
|||
InteractionPolicy *InteractionPolicy `bun:""` // InteractionPolicy for this status. If null then the default InteractionPolicy should be assumed for this status's Visibility. Always null for boost wrappers.
|
||||
PendingApproval *bool `bun:",nullzero,notnull,default:false"` // If true then status is a reply or boost wrapper that must be Approved by the reply-ee or boost-ee before being fully distributed.
|
||||
PreApproved bool `bun:"-"` // If true, then status is a reply to or boost wrapper of a status on our instance, has permission to do the interaction, and an Accept should be sent out for it immediately. Field not stored in the DB.
|
||||
ApprovedByURI string `bun:",nullzero"` // URI of an Accept Activity that approves the Announce or Create Activity that this status was/will be attached to.
|
||||
ApprovedByURI string `bun:",nullzero"` // URI of *either* an Accept Activity, or a ReplyAuthorization or AnnounceAuthorization, which approves the Announce, Create or interaction request Activity that this status was/will be attached to.
|
||||
}
|
||||
|
||||
// GetID implements timeline.Timelineable{}.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
"codeberg.org/gruf/go-kv/v2"
|
||||
"github.com/oklog/ulid"
|
||||
|
|
@ -33,62 +34,71 @@ const (
|
|||
randomRange = 631152381 // ~20 years in seconds
|
||||
)
|
||||
|
||||
// bigRandomRange contains randomRange as big.Int.
|
||||
var bigRandomRange = big.NewInt(randomRange)
|
||||
|
||||
// ULID represents a Universally Unique Lexicographically Sortable Identifier of 26 characters. See https://github.com/oklog/ulid
|
||||
type ULID string
|
||||
|
||||
// NewULID returns a new ULID string using the current time.
|
||||
func NewULID() string {
|
||||
ulid, err := ulid.New(
|
||||
ulid.Timestamp(time.Now()), rand.Reader,
|
||||
)
|
||||
// newAt returns a new ulid.ULID from timestamp,
|
||||
// else panics with caller's caller information.
|
||||
func newAt(ts uint64) string {
|
||||
ulid, err := ulid.New(ts, rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(gtserror.NewfAt(4, "error generating ulid: %w", err))
|
||||
}
|
||||
return ulid.String()
|
||||
}
|
||||
|
||||
// NewULID returns a new ULID
|
||||
// string using the current time.
|
||||
func NewULID() string {
|
||||
return newAt(ulid.Now())
|
||||
}
|
||||
|
||||
// NewULIDFromTime returns a new ULID string using
|
||||
// given time, or from current time on any error.
|
||||
func NewULIDFromTime(t time.Time) string {
|
||||
ts := ulid.Timestamp(t)
|
||||
if ts > ulid.MaxTime() {
|
||||
log.WarnKVs(nil, kv.Fields{
|
||||
{K: "caller", V: log.Caller(2)},
|
||||
{K: "caller", V: log.Caller(3)},
|
||||
{K: "value", V: t},
|
||||
{K: "msg", V: "invalid ulid time"},
|
||||
}...)
|
||||
ts = ulid.Now()
|
||||
}
|
||||
return ulid.MustNew(ts, rand.Reader).String()
|
||||
return newAt(ts)
|
||||
}
|
||||
|
||||
// NewRandomULID returns a new ULID string using a random time in an ~80 year range around the current datetime, or an error if something goes wrong.
|
||||
func NewRandomULID() (string, error) {
|
||||
b1, err := rand.Int(rand.Reader, big.NewInt(randomRange))
|
||||
// NewRandomULID returns a new ULID string using a random
|
||||
// time in an ~80 year range around the current datetime.
|
||||
func NewRandomULID() string {
|
||||
n1, err := rand.Int(rand.Reader, bigRandomRange)
|
||||
if err != nil {
|
||||
return "", err
|
||||
panic(gtserror.NewfAt(3, "error reading rand: %w", err))
|
||||
}
|
||||
r1 := time.Duration(int(b1.Int64()))
|
||||
|
||||
b2, err := rand.Int(rand.Reader, big.NewInt(randomRange))
|
||||
n2, err := rand.Int(rand.Reader, bigRandomRange)
|
||||
if err != nil {
|
||||
return "", err
|
||||
panic(gtserror.NewfAt(3, "error reading rand: %w", err))
|
||||
}
|
||||
r2 := -time.Duration(int(b2.Int64()))
|
||||
|
||||
arbitraryTime := time.Now().Add(r1 * time.Second).Add(r2 * time.Second)
|
||||
newUlid, err := ulid.New(ulid.Timestamp(arbitraryTime), rand.Reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return newUlid.String(), nil
|
||||
// Random addition and decrement durations.
|
||||
add := time.Duration(n1.Int64()) * time.Second
|
||||
dec := -time.Duration(n2.Int64()) * time.Second
|
||||
|
||||
// Return new ULID string from now.
|
||||
t := time.Now().Add(add).Add(dec)
|
||||
return newAt(ulid.Timestamp(t))
|
||||
}
|
||||
|
||||
// TimeFromULID parses a ULID string and returns the
|
||||
// encoded time.Time{}, or error with caller prefix.
|
||||
func TimeFromULID(id string) (time.Time, error) {
|
||||
parsed, err := ulid.ParseStrict(id)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
return time.Time{}, gtserror.NewfAt(3, "could not extract time (malformed ulid): %w", err)
|
||||
}
|
||||
|
||||
return ulid.Time(parsed.Time()), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,10 +82,7 @@ func (p *Processor) FollowCreate(ctx context.Context, requestingAccount *gtsmode
|
|||
|
||||
// Neither follows nor follow requests, so
|
||||
// create and store a new follow request.
|
||||
followID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
followID := id.NewRandomULID()
|
||||
followURI := uris.GenerateURIForFollow(requestingAccount.Username, followID)
|
||||
|
||||
fr := >smodel.FollowRequest{
|
||||
|
|
|
|||
|
|
@ -64,17 +64,12 @@ func (p *Processor) RuleGet(ctx context.Context, id string) (*apimodel.AdminInst
|
|||
|
||||
// RuleCreate adds a new rule to the instance.
|
||||
func (p *Processor) RuleCreate(ctx context.Context, form *apimodel.InstanceRuleCreateRequest) (*apimodel.AdminInstanceRule, gtserror.WithCode) {
|
||||
ruleID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating id for new instance rule: %s", err), "error creating rule ID")
|
||||
}
|
||||
|
||||
rule := >smodel.Rule{
|
||||
ID: ruleID,
|
||||
ID: id.NewRandomULID(),
|
||||
Text: form.Text,
|
||||
}
|
||||
|
||||
if err = p.state.DB.PutRule(ctx, rule); err != nil {
|
||||
if err := p.state.DB.PutRule(ctx, rule); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ func (p *Processor) Create(
|
|||
}
|
||||
|
||||
// Generate random client ID.
|
||||
clientID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
clientID := id.NewRandomULID()
|
||||
|
||||
// Generate + store app
|
||||
// to put in the database.
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ package fedi
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
)
|
||||
|
||||
|
|
@ -34,44 +32,18 @@ import (
|
|||
func (p *Processor) AcceptGet(
|
||||
ctx context.Context,
|
||||
requestedUser string,
|
||||
reqID string,
|
||||
) (interface{}, gtserror.WithCode) {
|
||||
// Authenticate incoming request, getting related accounts.
|
||||
auth, errWithCode := p.authenticate(ctx, requestedUser)
|
||||
intReqID string,
|
||||
) (any, gtserror.WithCode) {
|
||||
// Ensure valid request, intReq exists, etc.
|
||||
intReq, errWithCode := p.validateIntReqRequest(ctx, requestedUser, intReqID)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
if auth.handshakingURI != nil {
|
||||
// We're currently handshaking, which means
|
||||
// we don't know this account yet. This should
|
||||
// be a very rare race condition.
|
||||
err := gtserror.Newf("network race handshaking %s", auth.handshakingURI)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
receivingAcct := auth.receivingAcct
|
||||
|
||||
req, err := p.state.DB.GetInteractionRequestByID(ctx, reqID)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("db error getting interaction request %s: %w", reqID, err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
if req == nil || !req.IsAccepted() {
|
||||
// Request doesn't exist or hasn't been accepted.
|
||||
err := gtserror.Newf("interaction request %s not found", reqID)
|
||||
return nil, gtserror.NewErrorNotFound(err)
|
||||
}
|
||||
|
||||
if req.TargetAccountID != receivingAcct.ID {
|
||||
const text = "interaction request does not belong to receiving account"
|
||||
return nil, gtserror.NewErrorNotFound(errors.New(text))
|
||||
}
|
||||
|
||||
accept, err := p.converter.InteractionReqToASAccept(ctx, req)
|
||||
// Convert + serialize the Accept.
|
||||
accept, err := p.converter.InteractionReqToASAccept(ctx, intReq)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting accept: %w", err)
|
||||
err := gtserror.Newf("error converting to accept: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
57
internal/processing/fedi/authorization.go
Normal file
57
internal/processing/fedi/authorization.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package fedi
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
)
|
||||
|
||||
// AuthorizationGet handles the getting of a fedi/activitypub
|
||||
// representation of a local interaction authorization.
|
||||
//
|
||||
// It performs appropriate authentication before
|
||||
// returning a JSON serializable interface.
|
||||
func (p *Processor) AuthorizationGet(
|
||||
ctx context.Context,
|
||||
requestedUser string,
|
||||
intReqID string,
|
||||
) (any, gtserror.WithCode) {
|
||||
// Ensure valid request, intReq exists, etc.
|
||||
intReq, errWithCode := p.validateIntReqRequest(ctx, requestedUser, intReqID)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
// Convert + serialize the Authorization.
|
||||
authorization, err := p.converter.InteractionReqToASAuthorization(ctx, intReq)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting to authorization: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
data, err := ap.Serialize(authorization)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error serializing accept: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ package fedi
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
|
|
@ -81,3 +82,52 @@ func (p *Processor) authenticate(ctx context.Context, requestedUser string) (*co
|
|||
receivingAcct: receiver,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateIntReqRequest is a shortcut function
|
||||
// for returning an accepted interaction request
|
||||
// targeting `requestedUser`.
|
||||
func (p *Processor) validateIntReqRequest(
|
||||
ctx context.Context,
|
||||
requestedUser string,
|
||||
intReqID string,
|
||||
) (*gtsmodel.InteractionRequest, gtserror.WithCode) {
|
||||
// Authenticate incoming request, getting related accounts.
|
||||
auth, errWithCode := p.authenticate(ctx, requestedUser)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
if auth.handshakingURI != nil {
|
||||
// We're currently handshaking, which means we don't know
|
||||
// this account yet. This should be a very rare race condition.
|
||||
err := gtserror.Newf("network race handshaking %s", auth.handshakingURI)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// Fetch interaction request with the given ID.
|
||||
req, err := p.state.DB.GetInteractionRequestByID(ctx, intReqID)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("db error getting interaction request %s: %w", intReqID, err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// Ensure that this is an existing
|
||||
// and *accepted* interaction request.
|
||||
if req == nil || !req.IsAccepted() {
|
||||
const text = "interaction request not found"
|
||||
return nil, gtserror.NewErrorNotFound(errors.New(text))
|
||||
}
|
||||
|
||||
// Ensure interaction request was accepted
|
||||
// by the account in the request path.
|
||||
if req.TargetAccountID != auth.receivingAcct.ID {
|
||||
text := fmt.Sprintf(
|
||||
"account %s is not targeted by interaction request %s and therefore can't accept it",
|
||||
requestedUser, intReqID,
|
||||
)
|
||||
return nil, gtserror.NewErrorNotFound(errors.New(text))
|
||||
}
|
||||
|
||||
// All fine.
|
||||
return req, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,14 +65,16 @@ func (p *Processor) Accept(
|
|||
defer unlock()
|
||||
|
||||
// Mark the request as accepted
|
||||
// and generate a URI for it.
|
||||
// and generate URIs for it.
|
||||
req.AcceptedAt = time.Now()
|
||||
req.URI = uris.GenerateURIForAccept(acct.Username, req.ID)
|
||||
req.ResponseURI = uris.GenerateURIForAccept(acct.Username, req.ID)
|
||||
req.AuthorizationURI = uris.GenerateURIForAuthorization(acct.Username, req.ID)
|
||||
if err := p.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
req,
|
||||
"accepted_at",
|
||||
"uri",
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
|
|
@ -132,7 +134,7 @@ func (p *Processor) acceptLike(
|
|||
// Update the Like.
|
||||
req.Like.PendingApproval = util.Ptr(false)
|
||||
req.Like.PreApproved = false
|
||||
req.Like.ApprovedByURI = req.URI
|
||||
req.Like.ApprovedByURI = req.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
req.Like,
|
||||
|
|
@ -173,7 +175,7 @@ func (p *Processor) acceptReply(
|
|||
// Update the Reply.
|
||||
req.Reply.PendingApproval = util.Ptr(false)
|
||||
req.Reply.PreApproved = false
|
||||
req.Reply.ApprovedByURI = req.URI
|
||||
req.Reply.ApprovedByURI = req.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
req.Reply,
|
||||
|
|
@ -214,7 +216,7 @@ func (p *Processor) acceptAnnounce(
|
|||
// Update the Announce.
|
||||
req.Announce.PendingApproval = util.Ptr(false)
|
||||
req.Announce.PreApproved = false
|
||||
req.Announce.ApprovedByURI = req.URI
|
||||
req.Announce.ApprovedByURI = req.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
req.Announce,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func (suite *AcceptTestSuite) TestAccept() {
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.False(*dbStatus.PendingApproval)
|
||||
suite.Equal(dbReq.URI, dbStatus.ApprovedByURI)
|
||||
suite.Equal(dbReq.AuthorizationURI, dbStatus.ApprovedByURI)
|
||||
|
||||
// Wait for a notification
|
||||
// for interacting status.
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@ func (p *Processor) Reject(
|
|||
// Mark the request as rejected
|
||||
// and generate a URI for it.
|
||||
req.RejectedAt = time.Now()
|
||||
req.URI = uris.GenerateURIForReject(acct.Username, req.ID)
|
||||
req.ResponseURI = uris.GenerateURIForReject(acct.Username, req.ID)
|
||||
if err := p.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
req,
|
||||
"rejected_at",
|
||||
"uri",
|
||||
"response_uri",
|
||||
); err != nil {
|
||||
err := gtserror.Newf("db error updating interaction request: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ func (p *Processor) byURI(
|
|||
switch {
|
||||
case gtserror.IsUnretrievable(err),
|
||||
gtserror.IsWrongType(err),
|
||||
gtserror.NotPermitted(err):
|
||||
gtserror.IsNotPermitted(err):
|
||||
log.Debugf(ctx,
|
||||
"semi-expected error type looking up %s as status: %v",
|
||||
uri, err,
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account)
|
|||
|
||||
// Address the delete CC public.
|
||||
deleteCC := streams.NewActivityStreamsCcProperty()
|
||||
deleteCC.AppendIRI(ap.PublicURI())
|
||||
deleteCC.AppendIRI(ap.PublicIRI())
|
||||
delete.SetActivityStreamsCc(deleteCC)
|
||||
|
||||
// Send the Delete via the Actor's outbox.
|
||||
|
|
@ -491,12 +491,7 @@ func (f *federate) UndoAnnounce(ctx context.Context, boost *gtsmodel.Status) err
|
|||
}
|
||||
|
||||
// Recreate the ActivityStreams Announce.
|
||||
asAnnounce, err := f.converter.BoostToAS(
|
||||
ctx,
|
||||
boost,
|
||||
boost.Account,
|
||||
boost.BoostOfAccount,
|
||||
)
|
||||
asAnnounce, err := f.converter.BoostToAS(ctx, boost)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error converting boost to AS: %w", err)
|
||||
}
|
||||
|
|
@ -767,12 +762,7 @@ func (f *federate) Announce(ctx context.Context, boost *gtsmodel.Status) error {
|
|||
}
|
||||
|
||||
// Create the ActivityStreams Announce.
|
||||
announce, err := f.converter.BoostToAS(
|
||||
ctx,
|
||||
boost,
|
||||
boost.Account,
|
||||
boost.BoostOfAccount,
|
||||
)
|
||||
announce, err := f.converter.BoostToAS(ctx, boost)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error converting boost to AS: %w", err)
|
||||
}
|
||||
|
|
@ -1104,7 +1094,7 @@ func (f *federate) MoveAccount(ctx context.Context, account *gtsmodel.Account) e
|
|||
ap.AppendTo(move, followersIRI)
|
||||
|
||||
// Address the move CC public.
|
||||
ap.AppendCc(move, ap.PublicURI())
|
||||
ap.AppendCc(move, ap.PublicIRI())
|
||||
|
||||
// Send the Move via the Actor's outbox.
|
||||
if _, err := f.FederatingActor().Send(
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ func (p *clientAPI) CreateStatus(ctx context.Context, cMsg *messages.FromClientA
|
|||
// and/or notify the account that's being
|
||||
// interacted with (if it's local): they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestReply(ctx, status); err != nil {
|
||||
if err := p.utils.impoliteReplyRequest(ctx, status); err != nil {
|
||||
return gtserror.Newf("error pending reply: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -310,19 +310,22 @@ func (p *clientAPI) CreateStatus(ctx context.Context, cMsg *messages.FromClientA
|
|||
// URI attached.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: status.InReplyToID,
|
||||
TargetAccountID: status.InReplyToAccountID,
|
||||
TargetAccount: status.InReplyToAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Reply: status,
|
||||
URI: uris.GenerateURIForAccept(status.InReplyToAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: status.InReplyToID,
|
||||
TargetAccountID: status.InReplyToAccountID,
|
||||
TargetAccount: status.InReplyToAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.ReplyRequestSuffix),
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(false), // TODO: Change this in v0.21.0 when we only send out polite requests.
|
||||
Reply: status,
|
||||
ResponseURI: uris.GenerateURIForAccept(status.InReplyToAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(status.InReplyToAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -331,7 +334,7 @@ func (p *clientAPI) CreateStatus(ctx context.Context, cMsg *messages.FromClientA
|
|||
// Mark the status as now approved.
|
||||
status.PendingApproval = util.Ptr(false)
|
||||
status.PreApproved = false
|
||||
status.ApprovedByURI = approval.URI
|
||||
status.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
status,
|
||||
|
|
@ -494,7 +497,7 @@ func (p *clientAPI) CreateLike(ctx context.Context, cMsg *messages.FromClientAPI
|
|||
// and/or notify the account that's being
|
||||
// interacted with (if it's local): they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestFave(ctx, fave); err != nil {
|
||||
if err := p.utils.impoliteFaveRequest(ctx, fave); err != nil {
|
||||
return gtserror.Newf("error pending fave: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -517,19 +520,22 @@ func (p *clientAPI) CreateLike(ctx context.Context, cMsg *messages.FromClientAPI
|
|||
// URI attached.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: fave.StatusID,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Like: fave,
|
||||
URI: uris.GenerateURIForAccept(fave.TargetAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: fave.StatusID,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(fave.URI, gtsmodel.LikeRequestSuffix),
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false), // TODO: Change this in v0.21.0 when we only send out polite requests.
|
||||
Like: fave,
|
||||
ResponseURI: uris.GenerateURIForAccept(fave.TargetAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(fave.TargetAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -538,7 +544,7 @@ func (p *clientAPI) CreateLike(ctx context.Context, cMsg *messages.FromClientAPI
|
|||
// Mark the fave itself as now approved.
|
||||
fave.PendingApproval = util.Ptr(false)
|
||||
fave.PreApproved = false
|
||||
fave.ApprovedByURI = approval.URI
|
||||
fave.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
fave,
|
||||
|
|
@ -589,7 +595,7 @@ func (p *clientAPI) CreateAnnounce(ctx context.Context, cMsg *messages.FromClien
|
|||
// and/or notify the account that's being
|
||||
// interacted with (if it's local): they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestAnnounce(ctx, boost); err != nil {
|
||||
if err := p.utils.impoliteAnnounceRequest(ctx, boost); err != nil {
|
||||
return gtserror.Newf("error pending boost: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -612,19 +618,22 @@ func (p *clientAPI) CreateAnnounce(ctx context.Context, cMsg *messages.FromClien
|
|||
// URI attached.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: boost.BoostOfID,
|
||||
TargetAccountID: boost.BoostOfAccountID,
|
||||
TargetAccount: boost.BoostOfAccount,
|
||||
InteractingAccountID: boost.AccountID,
|
||||
InteractingAccount: boost.Account,
|
||||
InteractionURI: boost.URI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Announce: boost,
|
||||
URI: uris.GenerateURIForAccept(boost.BoostOfAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: boost.BoostOfID,
|
||||
TargetAccountID: boost.BoostOfAccountID,
|
||||
TargetAccount: boost.BoostOfAccount,
|
||||
InteractingAccountID: boost.AccountID,
|
||||
InteractingAccount: boost.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(boost.URI, gtsmodel.AnnounceRequestSuffix),
|
||||
InteractionURI: boost.URI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Polite: util.Ptr(false), // TODO: Change this in v0.21.0 when we only send out polite requests.
|
||||
Announce: boost,
|
||||
ResponseURI: uris.GenerateURIForAccept(boost.BoostOfAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(boost.BoostOfAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -633,7 +642,7 @@ func (p *clientAPI) CreateAnnounce(ctx context.Context, cMsg *messages.FromClien
|
|||
// Mark the boost itself as now approved.
|
||||
boost.PendingApproval = util.Ptr(false)
|
||||
boost.PreApproved = false
|
||||
boost.ApprovedByURI = approval.URI
|
||||
boost.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
boost,
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF
|
|||
case ap.ObjectNote:
|
||||
return p.fediAPI.CreateStatus(ctx, fMsg)
|
||||
|
||||
// REQUEST TO REPLY TO A STATUS
|
||||
case ap.ActivityReplyRequest:
|
||||
return p.fediAPI.CreateReplyRequest(ctx, fMsg)
|
||||
|
||||
// CREATE FOLLOW (request)
|
||||
case ap.ActivityFollow:
|
||||
return p.fediAPI.CreateFollowReq(ctx, fMsg)
|
||||
|
|
@ -96,10 +100,18 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF
|
|||
case ap.ActivityLike:
|
||||
return p.fediAPI.CreateLike(ctx, fMsg)
|
||||
|
||||
// REQUEST TO LIKE A STATUS
|
||||
case ap.ActivityLikeRequest:
|
||||
return p.fediAPI.CreateLikeRequest(ctx, fMsg)
|
||||
|
||||
// CREATE ANNOUNCE/BOOST
|
||||
case ap.ActivityAnnounce:
|
||||
return p.fediAPI.CreateAnnounce(ctx, fMsg)
|
||||
|
||||
// REQUEST TO BOOST A STATUS
|
||||
case ap.ActivityAnnounceRequest:
|
||||
return p.fediAPI.CreateAnnounceRequest(ctx, fMsg)
|
||||
|
||||
// CREATE BLOCK
|
||||
case ap.ActivityBlock:
|
||||
return p.fediAPI.CreateBlock(ctx, fMsg)
|
||||
|
|
@ -146,11 +158,15 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF
|
|||
case ap.ObjectNote:
|
||||
return p.fediAPI.AcceptReply(ctx, fMsg)
|
||||
|
||||
// ACCEPT (pending) POLITE REPLY REQUEST
|
||||
case ap.ActivityReplyRequest:
|
||||
return p.fediAPI.AcceptPoliteReplyRequest(ctx, fMsg)
|
||||
|
||||
// ACCEPT (pending) ANNOUNCE
|
||||
case ap.ActivityAnnounce:
|
||||
return p.fediAPI.AcceptAnnounce(ctx, fMsg)
|
||||
|
||||
// ACCEPT (remote) REPLY or ANNOUNCE
|
||||
// ACCEPT (remote) IMPOLITE REPLY or ANNOUNCE
|
||||
case ap.ObjectUnknown:
|
||||
return p.fediAPI.AcceptRemoteStatus(ctx, fMsg)
|
||||
}
|
||||
|
|
@ -219,6 +235,9 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF
|
|||
return gtserror.Newf("unhandled: %s %s", fMsg.APActivityType, fMsg.APObjectType)
|
||||
}
|
||||
|
||||
// CreateStatus handles the creation of a status/post sent as a Create message.
|
||||
// It is also capable of handling impolite reply requests to local + remote statuses,
|
||||
// ie., replies sent directly without doing the ReplyRequest process first.
|
||||
func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
var (
|
||||
status *gtsmodel.Status
|
||||
|
|
@ -291,7 +310,7 @@ func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
|
|||
// preapproved, then just notify the account
|
||||
// that's being interacted with: they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestReply(ctx, status); err != nil {
|
||||
if err := p.utils.impoliteReplyRequest(ctx, status); err != nil {
|
||||
return gtserror.Newf("error pending reply: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -306,20 +325,24 @@ func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
|
|||
// collection. Do the Accept immediately and
|
||||
// then process everything else as normal.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
// Store an already-accepted
|
||||
// impolite interaction request.
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: status.InReplyToID,
|
||||
TargetAccountID: status.InReplyToAccountID,
|
||||
TargetAccount: status.InReplyToAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Reply: status,
|
||||
URI: uris.GenerateURIForAccept(status.InReplyToAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: status.InReplyToID,
|
||||
TargetAccountID: status.InReplyToAccountID,
|
||||
TargetAccount: status.InReplyToAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.ReplyRequestSuffix),
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(false),
|
||||
Reply: status,
|
||||
ResponseURI: uris.GenerateURIForAccept(status.InReplyToAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(status.InReplyToAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -328,7 +351,7 @@ func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
|
|||
// Mark the status as now approved.
|
||||
status.PendingApproval = util.Ptr(false)
|
||||
status.PreApproved = false
|
||||
status.ApprovedByURI = approval.URI
|
||||
status.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
status,
|
||||
|
|
@ -365,6 +388,118 @@ func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
|
|||
return nil
|
||||
}
|
||||
|
||||
// CreateReplyRequest handles a polite ReplyRequest.
|
||||
// This is distinct from CreateStatus, which is capable
|
||||
// of handling both "normal" top-level status creation,
|
||||
// in addition to *impolite* reply requests.
|
||||
func (p *fediAPI) CreateReplyRequest(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
// Extract the ap model Statusable
|
||||
// set by the federating db.
|
||||
statusable, ok := fMsg.APObject.(ap.Statusable)
|
||||
if !ok {
|
||||
return gtserror.Newf("cannot cast %T -> ap.Statusable", fMsg.APObject)
|
||||
}
|
||||
|
||||
// Call RefreshStatus to parse and process the
|
||||
// statusable. This will also check permissions.
|
||||
replyURI := ap.GetJSONLDId(statusable).String()
|
||||
reply, _, err := p.federate.RefreshStatus(ctx,
|
||||
fMsg.Receiving.Username,
|
||||
>smodel.Status{
|
||||
URI: replyURI,
|
||||
Local: util.Ptr(false),
|
||||
},
|
||||
statusable,
|
||||
// Force refresh within 5min window.
|
||||
dereferencing.Fresh,
|
||||
)
|
||||
|
||||
switch {
|
||||
case err == nil:
|
||||
// All fine.
|
||||
|
||||
case gtserror.IsNotPermitted(err):
|
||||
// Reply is straight up not permitted by
|
||||
// the interaction policy of the status
|
||||
// it's replying to. Nothing more to do.
|
||||
log.Debugf(ctx,
|
||||
"dropping unpermitted ReplyRequest with instrument %s",
|
||||
replyURI,
|
||||
)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// There's some real error.
|
||||
return gtserror.Newf(
|
||||
"error processing ReplyRequest with instrument %s: %w",
|
||||
replyURI, err,
|
||||
)
|
||||
}
|
||||
|
||||
// The reply is permitted. Check if we
|
||||
// should send out an Accept immediately.
|
||||
manualApproval := *reply.PendingApproval && !reply.PreApproved
|
||||
if manualApproval {
|
||||
// The reply requires manual approval.
|
||||
//
|
||||
// Just notify target account about
|
||||
// the requested interaction.
|
||||
if err := p.surface.notifyPendingReply(ctx, reply); err != nil {
|
||||
return gtserror.Newf("error notifying pending reply: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The reply is automatically approved,
|
||||
// handle side effects of this.
|
||||
req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest)
|
||||
if !ok {
|
||||
return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel)
|
||||
}
|
||||
|
||||
// Mark the request as accepted.
|
||||
req.AcceptedAt = time.Now()
|
||||
req.ResponseURI = uris.GenerateURIForAccept(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
req.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
|
||||
// Update in the db.
|
||||
if err := p.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
req,
|
||||
"accepted_at",
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating interaction request: %w", err)
|
||||
}
|
||||
|
||||
// Send out the accept.
|
||||
if err := p.federate.AcceptInteraction(ctx, req); err != nil {
|
||||
log.Errorf(ctx, "error federating accept: %v", err)
|
||||
}
|
||||
|
||||
// Update stats for the replying account.
|
||||
if err := p.utils.incrementStatusesCount(ctx, fMsg.Requesting, reply); err != nil {
|
||||
log.Errorf(ctx, "error updating account stats: %v", err)
|
||||
}
|
||||
|
||||
// Timeline the reply + notify recipient(s).
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error timelining and notifying status: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the replied status;
|
||||
// uncache the prepared version from all timelines.
|
||||
p.surface.invalidateStatusFromTimelines(reply.InReplyToID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) CreatePollVote(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
// Cast poll vote type from the worker message.
|
||||
vote, ok := fMsg.GTSModel.(*gtsmodel.PollVote)
|
||||
|
|
@ -430,18 +565,18 @@ func (p *fediAPI) UpdatePollVote(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
}
|
||||
|
||||
// Get the origin status.
|
||||
status := vote.Poll.Status
|
||||
reply := vote.Poll.Status
|
||||
|
||||
if *status.Local {
|
||||
if *reply.Local {
|
||||
// These were poll votes in a local status, we need to
|
||||
// federate the updated status model with latest vote counts.
|
||||
if err := p.federate.UpdateStatus(ctx, status); err != nil {
|
||||
if err := p.federate.UpdateStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error federating status update: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Interaction counts changed, uncache from timelines.
|
||||
p.surface.invalidateStatusFromTimelines(status.ID)
|
||||
p.surface.invalidateStatusFromTimelines(reply.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -503,6 +638,8 @@ func (p *fediAPI) CreateFollowReq(ctx context.Context, fMsg *messages.FromFediAP
|
|||
return nil
|
||||
}
|
||||
|
||||
// CreateLike handles an impolite Like, ie., a Like sent directly.
|
||||
// This is different from the CreateLikeRequest function, which handles polite LikeRequests.
|
||||
func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
fave, ok := fMsg.GTSModel.(*gtsmodel.StatusFave)
|
||||
if !ok {
|
||||
|
|
@ -525,7 +662,7 @@ func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) er
|
|||
// preapproved, then just notify the account
|
||||
// that's being interacted with: they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestFave(ctx, fave); err != nil {
|
||||
if err := p.utils.impoliteFaveRequest(ctx, fave); err != nil {
|
||||
return gtserror.Newf("error pending fave: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -540,20 +677,24 @@ func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) er
|
|||
// collection. Do the Accept immediately and
|
||||
// then process everything else as normal.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
// Store an already-accepted
|
||||
// impolite interaction request.
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: fave.StatusID,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Like: fave,
|
||||
URI: uris.GenerateURIForAccept(fave.TargetAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: fave.StatusID,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(fave.URI, gtsmodel.LikeRequestSuffix),
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
Like: fave,
|
||||
ResponseURI: uris.GenerateURIForAccept(fave.TargetAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(fave.TargetAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -562,7 +703,7 @@ func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) er
|
|||
// Mark the fave itself as now approved.
|
||||
fave.PendingApproval = util.Ptr(false)
|
||||
fave.PreApproved = false
|
||||
fave.ApprovedByURI = approval.URI
|
||||
fave.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
fave,
|
||||
|
|
@ -591,6 +732,87 @@ func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) er
|
|||
return nil
|
||||
}
|
||||
|
||||
// CreateLikeRequest handles a polite LikeRequest, as
|
||||
// opposed to CreateLike, which handles *impolite* like
|
||||
// requests (ie., Likes sent directly).
|
||||
func (p *fediAPI) CreateLikeRequest(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest)
|
||||
if !ok {
|
||||
return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel)
|
||||
}
|
||||
|
||||
// At this point the not-yet-approved
|
||||
// interaction request, and the pending
|
||||
// fave, are both in the database.
|
||||
|
||||
if !req.Like.PreApproved {
|
||||
// The fave is *not* pre-approved, and
|
||||
// therefore requires manual approval.
|
||||
//
|
||||
// Just notify target account about
|
||||
// the requested interaction.
|
||||
if err := p.surface.notifyPendingFave(ctx, req.Like); err != nil {
|
||||
return gtserror.Newf("error notifying pending like: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// If it's pre-approved on the other hand
|
||||
// we can handle everything immediately.
|
||||
|
||||
// Mark the request as accepted.
|
||||
req.AcceptedAt = time.Now()
|
||||
req.ResponseURI = uris.GenerateURIForAccept(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
req.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
|
||||
// Update in the db.
|
||||
if err := p.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
req,
|
||||
"accepted_at",
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating interaction request: %w", err)
|
||||
}
|
||||
|
||||
// Send out the accept.
|
||||
if err := p.federate.AcceptInteraction(ctx, req); err != nil {
|
||||
log.Errorf(ctx, "error federating accept: %v", err)
|
||||
}
|
||||
|
||||
// Mark the fave as approved.
|
||||
req.Like.PendingApproval = util.Ptr(false)
|
||||
req.Like.ApprovedByURI = req.AuthorizationURI
|
||||
req.Like.PreApproved = false
|
||||
|
||||
// Update in the db.
|
||||
if err := p.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
req.Like,
|
||||
"pending_approval",
|
||||
"approved_by_uri",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating status fave: %w", err)
|
||||
}
|
||||
|
||||
// Notify the faved account.
|
||||
if err := p.surface.notifyFave(ctx, req.Like); err != nil {
|
||||
log.Errorf(ctx, "error notifying fave: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the faved status;
|
||||
// uncache the prepared version from all timelines.
|
||||
p.surface.invalidateStatusFromTimelines(req.Like.StatusID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
boost, ok := fMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
|
|
@ -610,7 +832,7 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
)
|
||||
if err != nil {
|
||||
if gtserror.IsUnretrievable(err) ||
|
||||
gtserror.NotPermitted(err) {
|
||||
gtserror.IsNotPermitted(err) {
|
||||
// Boosted status domain blocked, or
|
||||
// otherwise not permitted, nothing to do.
|
||||
log.Debugf(ctx, "skipping announce: %v", err)
|
||||
|
|
@ -632,7 +854,7 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
// preapproved, then just notify the account
|
||||
// that's being interacted with: they can
|
||||
// approve or deny the interaction later.
|
||||
if err := p.utils.requestAnnounce(ctx, boost); err != nil {
|
||||
if err := p.utils.impoliteAnnounceRequest(ctx, boost); err != nil {
|
||||
return gtserror.Newf("error pending boost: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -647,20 +869,24 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
// collection. Do the Accept immediately and
|
||||
// then process everything else as normal.
|
||||
|
||||
// Store an already-accepted interaction request.
|
||||
id := id.NewULID()
|
||||
// Store an already-accepted
|
||||
// impolite interaction request.
|
||||
requestID := id.NewULID()
|
||||
approval := >smodel.InteractionRequest{
|
||||
ID: id,
|
||||
StatusID: boost.BoostOfID,
|
||||
TargetAccountID: boost.BoostOfAccountID,
|
||||
TargetAccount: boost.BoostOfAccount,
|
||||
InteractingAccountID: boost.AccountID,
|
||||
InteractingAccount: boost.Account,
|
||||
InteractionURI: boost.URI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Announce: boost,
|
||||
URI: uris.GenerateURIForAccept(boost.BoostOfAccount.Username, id),
|
||||
AcceptedAt: time.Now(),
|
||||
ID: requestID,
|
||||
TargetStatusID: boost.BoostOfID,
|
||||
TargetAccountID: boost.BoostOfAccountID,
|
||||
TargetAccount: boost.BoostOfAccount,
|
||||
InteractingAccountID: boost.AccountID,
|
||||
InteractingAccount: boost.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(boost.URI, gtsmodel.AnnounceRequestSuffix),
|
||||
InteractionURI: boost.URI,
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Polite: util.Ptr(false),
|
||||
Announce: boost,
|
||||
ResponseURI: uris.GenerateURIForAccept(boost.BoostOfAccount.Username, requestID),
|
||||
AuthorizationURI: uris.GenerateURIForAuthorization(boost.BoostOfAccount.Username, requestID),
|
||||
AcceptedAt: time.Now(),
|
||||
}
|
||||
if err := p.state.DB.PutInteractionRequest(ctx, approval); err != nil {
|
||||
return gtserror.Newf("db error putting pre-approved interaction request: %w", err)
|
||||
|
|
@ -669,7 +895,7 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
// Mark the boost itself as now approved.
|
||||
boost.PendingApproval = util.Ptr(false)
|
||||
boost.PreApproved = false
|
||||
boost.ApprovedByURI = approval.URI
|
||||
boost.ApprovedByURI = approval.AuthorizationURI
|
||||
if err := p.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
boost,
|
||||
|
|
@ -708,6 +934,103 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) CreateAnnounceRequest(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest)
|
||||
if !ok {
|
||||
return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel)
|
||||
}
|
||||
|
||||
// At this point the not-yet-handled interaction req
|
||||
// is in the database, but the announce isn't yet.
|
||||
//
|
||||
// We can check permissions for the announce *and*
|
||||
// put it in the db (if acceptable) by doing Enrich.
|
||||
boost, err := p.federate.EnrichAnnounce(
|
||||
ctx,
|
||||
req.Announce,
|
||||
fMsg.Receiving.Username,
|
||||
)
|
||||
|
||||
switch {
|
||||
case err == nil:
|
||||
// All fine.
|
||||
|
||||
case gtserror.IsNotPermitted(err):
|
||||
// Announce is straight up not permitted
|
||||
// by the interaction policy of the status
|
||||
// it's targeting. Nothing more to do.
|
||||
log.Debugf(ctx,
|
||||
"dropping unpermitted AnnounceRequest with instrument %s",
|
||||
req.Announce.URI,
|
||||
)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// There's some real error.
|
||||
return gtserror.Newf(
|
||||
"error processing AnnounceRequest with instrument %s: %w",
|
||||
req.Announce.URI, err,
|
||||
)
|
||||
}
|
||||
|
||||
// The announce is permitted. Check if we
|
||||
// should send out an Accept immediately.
|
||||
manualApproval := *boost.PendingApproval && !boost.PreApproved
|
||||
if manualApproval {
|
||||
// The announce requires manual approval.
|
||||
//
|
||||
// Just notify target account about
|
||||
// the requested interaction.
|
||||
if err := p.surface.notifyPendingAnnounce(ctx, boost); err != nil {
|
||||
return gtserror.Newf("error notifying pending announce: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The announce is automatically approved,
|
||||
// mark the request as accepted.
|
||||
req.AcceptedAt = time.Now()
|
||||
req.ResponseURI = uris.GenerateURIForAccept(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
req.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
req.TargetAccount.Username, req.ID,
|
||||
)
|
||||
|
||||
// Update in the db.
|
||||
if err := p.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
req,
|
||||
"accepted_at",
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
); err != nil {
|
||||
return gtserror.Newf("db error updating interaction request: %w", err)
|
||||
}
|
||||
|
||||
// Send out the accept.
|
||||
if err := p.federate.AcceptInteraction(ctx, req); err != nil {
|
||||
log.Errorf(ctx, "error federating accept: %v", err)
|
||||
}
|
||||
|
||||
// Update stats for the boosting account.
|
||||
if err := p.utils.incrementStatusesCount(ctx, fMsg.Requesting, boost); err != nil {
|
||||
log.Errorf(ctx, "error updating account stats: %v", err)
|
||||
}
|
||||
|
||||
// Timeline the boost + notify recipient(s).
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, boost); err != nil {
|
||||
log.Errorf(ctx, "error timelining and notifying status: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the boosted status;
|
||||
// uncache the prepared version from all timelines.
|
||||
p.surface.invalidateStatusFromTimelines(boost.BoostOfID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) CreateBlock(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
block, ok := fMsg.GTSModel.(*gtsmodel.Block)
|
||||
if !ok {
|
||||
|
|
@ -842,29 +1165,29 @@ func (p *fediAPI) AcceptLike(ctx context.Context, fMsg *messages.FromFediAPI) er
|
|||
}
|
||||
|
||||
func (p *fediAPI) AcceptReply(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
status, ok := fMsg.GTSModel.(*gtsmodel.Status)
|
||||
reply, ok := fMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel)
|
||||
}
|
||||
|
||||
// Update stats for the actor account.
|
||||
if err := p.utils.incrementStatusesCount(ctx, status.Account, status); err != nil {
|
||||
if err := p.utils.incrementStatusesCount(ctx, reply.Account, reply); err != nil {
|
||||
log.Errorf(ctx, "error updating account stats: %v", err)
|
||||
}
|
||||
|
||||
// Timeline and notify the status.
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, status); err != nil {
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error timelining and notifying status: %v", err)
|
||||
}
|
||||
|
||||
// Send out the reply again, fully this time.
|
||||
if err := p.federate.CreateStatus(ctx, status); err != nil {
|
||||
if err := p.federate.CreateStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error federating announce: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the replied-to status;
|
||||
// uncache the prepared version from all timelines.
|
||||
p.surface.invalidateStatusFromTimelines(status.InReplyToID)
|
||||
p.surface.invalidateStatusFromTimelines(reply.InReplyToID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -893,9 +1216,9 @@ func (p *fediAPI) AcceptRemoteStatus(ctx context.Context, fMsg *messages.FromFed
|
|||
// barebones status and insert it into the database,
|
||||
// if indeed it's actually a status URI we can fetch.
|
||||
//
|
||||
// This will also check whether the given AcceptIRI
|
||||
// This will also check whether the given approvedByURI
|
||||
// actually grants permission for this status.
|
||||
status, _, err := p.federate.RefreshStatus(ctx,
|
||||
reply, _, err := p.federate.RefreshStatus(ctx,
|
||||
fMsg.Receiving.Username,
|
||||
bareStatus,
|
||||
nil, nil,
|
||||
|
|
@ -906,23 +1229,73 @@ func (p *fediAPI) AcceptRemoteStatus(ctx context.Context, fMsg *messages.FromFed
|
|||
|
||||
// No error means it was indeed a remote status, and the
|
||||
// given approvedByURI permitted it. Timeline and notify it.
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, status); err != nil {
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error timelining and notifying status: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the interacted status;
|
||||
// uncache the prepared version from all timelines.
|
||||
if status.InReplyToID != "" {
|
||||
p.surface.invalidateStatusFromTimelines(status.InReplyToID)
|
||||
if reply.InReplyToID != "" {
|
||||
p.surface.invalidateStatusFromTimelines(reply.InReplyToID)
|
||||
}
|
||||
|
||||
if status.BoostOfID != "" {
|
||||
p.surface.invalidateStatusFromTimelines(status.BoostOfID)
|
||||
if reply.BoostOfID != "" {
|
||||
p.surface.invalidateStatusFromTimelines(reply.BoostOfID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) AcceptPoliteReplyRequest(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
if util.IsNil(fMsg.GTSModel) {
|
||||
// If the interaction request is nil, this
|
||||
// must be an accept of a remote ReplyRequest
|
||||
// not targeting one of our statuses.
|
||||
//
|
||||
// Just pass it to the AcceptRemoteStatus
|
||||
// func to do dereferencing + side effects.
|
||||
log.Debug(ctx, "accepting remote ReplyRequest for remote reply")
|
||||
return p.AcceptRemoteStatus(ctx, fMsg)
|
||||
}
|
||||
|
||||
// If the interaction request is not nil, this will
|
||||
// be an accept of one of our replies to a remote.
|
||||
//
|
||||
// Since the int req + reply have already been updated
|
||||
// in the federatingDB, we just need to do side effects.
|
||||
intReq, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest)
|
||||
if !ok {
|
||||
return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel)
|
||||
}
|
||||
|
||||
// Ensure reply populated.
|
||||
reply := intReq.Reply
|
||||
if err := p.state.DB.PopulateStatus(ctx, reply); err != nil {
|
||||
return gtserror.Newf("error populating status: %w", err)
|
||||
}
|
||||
|
||||
// Update stats for the actor account.
|
||||
if err := p.utils.incrementStatusesCount(ctx, reply.Account, reply); err != nil {
|
||||
log.Errorf(ctx, "error updating account stats: %v", err)
|
||||
}
|
||||
|
||||
// Timeline and notify the status.
|
||||
if err := p.surface.timelineAndNotifyStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error timelining and notifying status: %v", err)
|
||||
}
|
||||
|
||||
// Send out the reply with approval attached.
|
||||
if err := p.federate.CreateStatus(ctx, reply); err != nil {
|
||||
log.Errorf(ctx, "error federating announce: %v", err)
|
||||
}
|
||||
|
||||
// Interaction counts changed on the replied-to status;
|
||||
// uncache the prepared version from all timelines.
|
||||
p.surface.invalidateStatusFromTimelines(reply.InReplyToID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fediAPI) AcceptAnnounce(ctx context.Context, fMsg *messages.FromFediAPI) error {
|
||||
boost, ok := fMsg.GTSModel.(*gtsmodel.Status)
|
||||
if !ok {
|
||||
|
|
@ -1169,7 +1542,7 @@ func (p *fediAPI) RejectReply(ctx context.Context, fMsg *messages.FromFediAPI) e
|
|||
// be in the database, we just need to do side effects.
|
||||
|
||||
// Get the rejected status.
|
||||
status, err := p.state.DB.GetStatusByURI(
|
||||
reply, err := p.state.DB.GetStatusByURI(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
req.InteractionURI,
|
||||
)
|
||||
|
|
@ -1189,7 +1562,7 @@ func (p *fediAPI) RejectReply(ctx context.Context, fMsg *messages.FromFediAPI) e
|
|||
// Perform the actual status deletion.
|
||||
if err := p.utils.wipeStatus(
|
||||
ctx,
|
||||
status,
|
||||
reply,
|
||||
deleteAttachments,
|
||||
copyToSinBin,
|
||||
); err != nil {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package workers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
|
@ -26,11 +27,13 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/messages"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/stream"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
|
|
@ -781,6 +784,123 @@ func (suite *FromFediAPITestSuite) TestUpdateNote() {
|
|||
}
|
||||
}
|
||||
|
||||
func (suite *FromFediAPITestSuite) TestCreateReplyRequest() {
|
||||
var (
|
||||
ctx = suite.T().Context()
|
||||
testStructs = testrig.SetupTestStructs(rMediaPath, rTemplatePath)
|
||||
requesting = suite.testAccounts["remote_account_1"]
|
||||
receiving = suite.testAccounts["admin_account"]
|
||||
testStatus = suite.testStatuses["admin_account_status_1"]
|
||||
intReqURI = "http://fossbros-anonymous.io/requests/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
intURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/87fb1478-ac46-406a-8463-96ce05645219"
|
||||
jsonStr = `{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://gotosocial.org/ns",
|
||||
{
|
||||
"sensitive": "as:sensitive"
|
||||
}
|
||||
],
|
||||
"type": "ReplyRequest",
|
||||
"id": "` + intReqURI + `",
|
||||
"actor": "` + requesting.URI + `",
|
||||
"object": "` + testStatus.URI + `",
|
||||
"to": "` + receiving.URI + `",
|
||||
"instrument": {
|
||||
"attributedTo": "` + requesting.URI + `",
|
||||
"cc": "` + requesting.FollowersURI + `",
|
||||
"content": "\u003cp\u003ethis is a reply!\u003c/p\u003e",
|
||||
"id": "` + intURI + `",
|
||||
"inReplyTo": "` + testStatus.URI + `",
|
||||
"tag": {
|
||||
"href": "` + receiving.URI + `",
|
||||
"name": "@` + receiving.Username + `@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}
|
||||
}`
|
||||
)
|
||||
defer testrig.TearDownTestStructs(testStructs)
|
||||
|
||||
suite.T().Logf("testing reply request:\n\n%s", jsonStr)
|
||||
|
||||
// Decode the reply request + embedded statusable.
|
||||
t, err := ap.DecodeType(ctx, io.NopCloser(bytes.NewBufferString(jsonStr)))
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
replyReq := t.(vocab.GoToSocialReplyRequest)
|
||||
statusable := replyReq.GetActivityStreamsInstrument().At(0).GetActivityStreamsNote().(ap.Statusable)
|
||||
|
||||
// Create a pending interaction request in the
|
||||
// database, as though the reply req had already
|
||||
// passed through the federatingdb function.
|
||||
intReq := >smodel.InteractionRequest{
|
||||
ID: id.NewULID(),
|
||||
TargetStatusID: testStatus.ID,
|
||||
TargetStatus: testStatus,
|
||||
TargetAccountID: receiving.ID,
|
||||
TargetAccount: receiving,
|
||||
InteractingAccountID: requesting.ID,
|
||||
InteractingAccount: requesting,
|
||||
InteractionRequestURI: intReqURI,
|
||||
InteractionURI: ap.GetJSONLDId(statusable).String(),
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(true),
|
||||
Reply: nil, // Not settable yet.
|
||||
}
|
||||
if err := testStructs.State.DB.PutInteractionRequest(ctx, intReq); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Process the message.
|
||||
if err = testStructs.Processor.Workers().ProcessFromFediAPI(
|
||||
ctx,
|
||||
&messages.FromFediAPI{
|
||||
APObjectType: ap.ActivityReplyRequest,
|
||||
APActivityType: ap.ActivityCreate,
|
||||
GTSModel: intReq,
|
||||
APObject: statusable,
|
||||
Receiving: receiving,
|
||||
Requesting: requesting,
|
||||
},
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// The interaction request should be accepted.
|
||||
intReq, err = testStructs.State.DB.GetInteractionRequestByID(ctx, intReq.ID)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.WithinDuration(time.Now(), intReq.AcceptedAt, 1*time.Minute)
|
||||
suite.NotEmpty(intReq.AuthorizationURI)
|
||||
suite.NotEmpty(intReq.ResponseURI)
|
||||
|
||||
// Federator should send out an Accept that looks something like:
|
||||
//
|
||||
// {
|
||||
// "@context": [
|
||||
// "https://gotosocial.org/ns",
|
||||
// "https://www.w3.org/ns/activitystreams"
|
||||
// ],
|
||||
// "actor": "http://localhost:8080/users/admin",
|
||||
// "id": "http://localhost:8080/users/admin/accepts/01K2CV90660VRPZM39R35NMSG9",
|
||||
// "object": {
|
||||
// "actor": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
// "id": "http://fossbros-anonymous.io/requests/87fb1478-ac46-406a-8463-96ce05645219",
|
||||
// "instrument": "http://fossbros-anonymous.io/users/foss_satan/statuses/87fb1478-ac46-406a-8463-96ce05645219",
|
||||
// "object": "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
||||
// "type": "ReplyRequest"
|
||||
// },
|
||||
// "result": "http://localhost:8080/users/admin/authorizations/01K2CV90660VRPZM39R35NMSG9",
|
||||
// "to": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
// "type": "Accept"
|
||||
// }
|
||||
}
|
||||
|
||||
func TestFromFederatorTestSuite(t *testing.T) {
|
||||
suite.Run(t, &FromFediAPITestSuite{})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,9 +526,13 @@ func (u *utils) decrementFollowRequestsCount(
|
|||
return nil
|
||||
}
|
||||
|
||||
// requestFave stores an interaction request
|
||||
// impoliteFaveRequest stores an interaction request
|
||||
// for the given fave, and notifies the interactee.
|
||||
func (u *utils) requestFave(
|
||||
//
|
||||
// It should be used only when an actor has sent a Like
|
||||
// directly in response to a post that requires approval
|
||||
// for it, instead of sending a LikeRequest.
|
||||
func (u *utils) impoliteFaveRequest(
|
||||
ctx context.Context,
|
||||
fave *gtsmodel.StatusFave,
|
||||
) error {
|
||||
|
|
@ -555,8 +559,8 @@ func (u *utils) requestFave(
|
|||
return nil
|
||||
}
|
||||
|
||||
// Create + store new interaction request.
|
||||
req = typeutils.StatusFaveToInteractionRequest(fave)
|
||||
// Create + store new impolite interaction request.
|
||||
req = typeutils.StatusFaveToImpoliteInteractionRequest(fave)
|
||||
if err := u.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
return gtserror.Newf("db error storing interaction request: %w", err)
|
||||
}
|
||||
|
|
@ -569,9 +573,13 @@ func (u *utils) requestFave(
|
|||
return nil
|
||||
}
|
||||
|
||||
// requestReply stores an interaction request
|
||||
// impoliteReplyRequest stores an interaction request
|
||||
// for the given reply, and notifies the interactee.
|
||||
func (u *utils) requestReply(
|
||||
//
|
||||
// It should be used only when an actor has sent a reply
|
||||
// directly in response to a post that requires approval
|
||||
// for it, instead of sending a ReplyRequest.
|
||||
func (u *utils) impoliteReplyRequest(
|
||||
ctx context.Context,
|
||||
reply *gtsmodel.Status,
|
||||
) error {
|
||||
|
|
@ -598,8 +606,8 @@ func (u *utils) requestReply(
|
|||
return nil
|
||||
}
|
||||
|
||||
// Create + store interaction request.
|
||||
req = typeutils.StatusToInteractionRequest(reply)
|
||||
// Create + store impolite interaction request.
|
||||
req = typeutils.StatusToImpoliteInteractionRequest(reply)
|
||||
if err := u.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
return gtserror.Newf("db error storing interaction request: %w", err)
|
||||
}
|
||||
|
|
@ -612,9 +620,13 @@ func (u *utils) requestReply(
|
|||
return nil
|
||||
}
|
||||
|
||||
// requestAnnounce stores an interaction request
|
||||
// impoliteAnnounceRequest stores an interaction request
|
||||
// for the given announce, and notifies the interactee.
|
||||
func (u *utils) requestAnnounce(
|
||||
//
|
||||
// It should be used only when an actor has sent an Announce
|
||||
// directly in response to a post that requires approval
|
||||
// for it, instead of sending an AnnounceRequest.
|
||||
func (u *utils) impoliteAnnounceRequest(
|
||||
ctx context.Context,
|
||||
boost *gtsmodel.Status,
|
||||
) error {
|
||||
|
|
@ -641,8 +653,8 @@ func (u *utils) requestAnnounce(
|
|||
return nil
|
||||
}
|
||||
|
||||
// Create + store interaction request.
|
||||
req = typeutils.StatusToInteractionRequest(boost)
|
||||
// Create + store impolite interaction request.
|
||||
req = typeutils.StatusToImpoliteInteractionRequest(boost)
|
||||
if err := u.state.DB.PutInteractionRequest(ctx, req); err != nil {
|
||||
return gtserror.Newf("db error storing interaction request: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -77,13 +76,8 @@ func (t *transport) DereferenceInstance(ctx context.Context, iri *url.URL) (*gts
|
|||
|
||||
// we couldn't dereference the instance using any of the known methods, so just return a minimal representation
|
||||
log.Debugf(ctx, "returning minimal representation of instance %s", iri.Host)
|
||||
id, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating new id for instance %s: %s", iri.Host, err)
|
||||
}
|
||||
|
||||
return >smodel.Instance{
|
||||
ID: id,
|
||||
ID: id.NewRandomULID(),
|
||||
Domain: iri.Host,
|
||||
URI: iri.String(),
|
||||
}, nil
|
||||
|
|
@ -166,13 +160,8 @@ func (t *transport) dereferenceByAPIV1Instance(
|
|||
contactUsername = apiResp.ContactAccount.Username
|
||||
}
|
||||
|
||||
ulid, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := >smodel.Instance{
|
||||
ID: ulid,
|
||||
ID: id.NewRandomULID(),
|
||||
Domain: iri.Host,
|
||||
Title: apiResp.Title,
|
||||
URI: iri.Scheme + "://" + iri.Host,
|
||||
|
|
@ -207,13 +196,8 @@ func (t *transport) dereferenceByNodeInfo(
|
|||
//
|
||||
// Start building out the bare minimum
|
||||
// instance model, we'll add to it if we can.
|
||||
id, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error creating new id for instance %s: %w", iri.Host, err)
|
||||
}
|
||||
|
||||
i := >smodel.Instance{
|
||||
ID: id,
|
||||
ID: id.NewRandomULID(),
|
||||
Domain: iri.Host,
|
||||
URI: iri.String(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -444,8 +444,8 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
|
|||
|
||||
// Set approvedByURI if present,
|
||||
// for later dereferencing.
|
||||
if ipa, ok := statusable.(ap.InteractionPolicyAware); ok {
|
||||
approvedByURI := ap.GetApprovedBy(ipa)
|
||||
if wab, ok := statusable.(ap.WithApprovedBy); ok {
|
||||
approvedByURI := ap.GetApprovedBy(wab)
|
||||
if approvedByURI != nil {
|
||||
status.ApprovedByURI = approvedByURI.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,17 +104,18 @@ func (c *Converter) StatusToBoost(
|
|||
return boost, nil
|
||||
}
|
||||
|
||||
func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRequest {
|
||||
func StatusToImpoliteInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRequest {
|
||||
reqID := id.NewULIDFromTime(status.CreatedAt)
|
||||
|
||||
var (
|
||||
targetID string
|
||||
target *gtsmodel.Status
|
||||
targetAccountID string
|
||||
targetAccount *gtsmodel.Account
|
||||
interactionType gtsmodel.InteractionType
|
||||
reply *gtsmodel.Status
|
||||
announce *gtsmodel.Status
|
||||
targetID string
|
||||
target *gtsmodel.Status
|
||||
targetAccountID string
|
||||
targetAccount *gtsmodel.Account
|
||||
interactionRequestURI string
|
||||
interactionType gtsmodel.InteractionType
|
||||
reply *gtsmodel.Status
|
||||
announce *gtsmodel.Status
|
||||
)
|
||||
|
||||
if status.InReplyToID != "" {
|
||||
|
|
@ -123,6 +124,7 @@ func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRe
|
|||
target = status.InReplyTo
|
||||
targetAccountID = status.InReplyToAccountID
|
||||
targetAccount = status.InReplyToAccount
|
||||
interactionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.ReplyRequestSuffix)
|
||||
interactionType = gtsmodel.InteractionReply
|
||||
reply = status
|
||||
} else {
|
||||
|
|
@ -131,41 +133,43 @@ func StatusToInteractionRequest(status *gtsmodel.Status) *gtsmodel.InteractionRe
|
|||
target = status.BoostOf
|
||||
targetAccountID = status.BoostOfAccountID
|
||||
targetAccount = status.BoostOfAccount
|
||||
interactionRequestURI = gtsmodel.ForwardCompatibleInteractionRequestURI(status.URI, gtsmodel.AnnounceRequestSuffix)
|
||||
interactionType = gtsmodel.InteractionAnnounce
|
||||
announce = status
|
||||
}
|
||||
|
||||
return >smodel.InteractionRequest{
|
||||
ID: reqID,
|
||||
CreatedAt: status.CreatedAt,
|
||||
StatusID: targetID,
|
||||
Status: target,
|
||||
TargetAccountID: targetAccountID,
|
||||
TargetAccount: targetAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: interactionType,
|
||||
Reply: reply,
|
||||
Announce: announce,
|
||||
ID: reqID,
|
||||
TargetStatusID: targetID,
|
||||
TargetStatus: target,
|
||||
TargetAccountID: targetAccountID,
|
||||
TargetAccount: targetAccount,
|
||||
InteractingAccountID: status.AccountID,
|
||||
InteractingAccount: status.Account,
|
||||
InteractionRequestURI: interactionRequestURI,
|
||||
InteractionURI: status.URI,
|
||||
InteractionType: interactionType,
|
||||
Polite: util.Ptr(false),
|
||||
Reply: reply,
|
||||
Announce: announce,
|
||||
}
|
||||
}
|
||||
|
||||
func StatusFaveToInteractionRequest(fave *gtsmodel.StatusFave) *gtsmodel.InteractionRequest {
|
||||
func StatusFaveToImpoliteInteractionRequest(fave *gtsmodel.StatusFave) *gtsmodel.InteractionRequest {
|
||||
reqID := id.NewULIDFromTime(fave.CreatedAt)
|
||||
|
||||
return >smodel.InteractionRequest{
|
||||
ID: reqID,
|
||||
CreatedAt: fave.CreatedAt,
|
||||
StatusID: fave.StatusID,
|
||||
Status: fave.Status,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Like: fave,
|
||||
ID: reqID,
|
||||
TargetStatusID: fave.StatusID,
|
||||
TargetStatus: fave.Status,
|
||||
TargetAccountID: fave.TargetAccountID,
|
||||
TargetAccount: fave.TargetAccount,
|
||||
InteractingAccountID: fave.AccountID,
|
||||
InteractingAccount: fave.Account,
|
||||
InteractionRequestURI: gtsmodel.ForwardCompatibleInteractionRequestURI(fave.URI, gtsmodel.LikeRequestSuffix),
|
||||
InteractionURI: fave.URI,
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
Like: fave,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,6 +25,8 @@ import (
|
|||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/uris"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
"code.superseriousbusiness.org/gotosocial/testrig"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
|
@ -947,6 +949,264 @@ func (suite *InternalToASTestSuite) TestStatusToASWithMentions() {
|
|||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASPoliteApproved() {
|
||||
ctx := suite.T().Context()
|
||||
|
||||
// Take a status from admin that replies to turtle.
|
||||
testStatus := new(gtsmodel.Status)
|
||||
*testStatus = *suite.testStatuses["admin_account_status_5"]
|
||||
|
||||
// Take corresponding interaction request.
|
||||
intReq := new(gtsmodel.InteractionRequest)
|
||||
*intReq = *suite.testInteractionRequests["admin_account_reply_turtle"]
|
||||
|
||||
// Mark the status as approved by updating the
|
||||
// status + corresponding interaction request.
|
||||
username := suite.testAccounts["local_account_2"].Username
|
||||
intReq.ResponseURI = uris.GenerateURIForAccept(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AcceptedAt = testrig.TimeMustParse("2024-11-01T11:00:00+02:00")
|
||||
|
||||
// Mark it as polite too.
|
||||
intReq.Polite = util.Ptr(true)
|
||||
|
||||
if err := suite.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
intReq,
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
"accepted_at",
|
||||
"polite",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
testStatus.ApprovedByURI = intReq.AuthorizationURI
|
||||
if err := suite.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
testStatus,
|
||||
"approved_by_uri",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"sensitive": "as:sensitive"
|
||||
}
|
||||
],
|
||||
"approvedBy": "http://localhost:8080/users/1happyturtle/accepts/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"attachment": [],
|
||||
"attributedTo": "http://localhost:8080/users/admin",
|
||||
"cc": [
|
||||
"http://localhost:8080/users/admin/followers",
|
||||
"http://localhost:8080/users/1happyturtle"
|
||||
],
|
||||
"content": "\u003cp\u003eHi \u003cspan class=\"h-card\"\u003e\u003ca href=\"http://localhost:8080/@1happyturtle\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\"\u003e@\u003cspan\u003e1happyturtle\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, can I reply?\u003c/p\u003e",
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
"inReplyTo": "http://localhost:8080/users/1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
"interactionPolicy": {
|
||||
"canAnnounce": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canLike": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canReply": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
}
|
||||
},
|
||||
"published": "2024-02-20T12:41:37+02:00",
|
||||
"replies": {
|
||||
"first": {
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true",
|
||||
"next": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true\u0026only_other_accounts=false",
|
||||
"partOf": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "CollectionPage"
|
||||
},
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "Collection"
|
||||
},
|
||||
"replyAuthorization": "http://localhost:8080/users/1happyturtle/authorizations/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"sensitive": false,
|
||||
"summary": "",
|
||||
"tag": {
|
||||
"href": "http://localhost:8080/users/1happyturtle",
|
||||
"name": "@1happyturtle@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note",
|
||||
"url": "http://localhost:8080/@admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ"
|
||||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASPImpoliteApproved() {
|
||||
ctx := suite.T().Context()
|
||||
|
||||
// Take a status from admin that replies to turtle.
|
||||
testStatus := new(gtsmodel.Status)
|
||||
*testStatus = *suite.testStatuses["admin_account_status_5"]
|
||||
|
||||
// Take corresponding interaction request.
|
||||
intReq := new(gtsmodel.InteractionRequest)
|
||||
*intReq = *suite.testInteractionRequests["admin_account_reply_turtle"]
|
||||
|
||||
// Mark the status as approved by updating the
|
||||
// status + corresponding interaction request.
|
||||
username := suite.testAccounts["local_account_2"].Username
|
||||
intReq.ResponseURI = uris.GenerateURIForAccept(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AuthorizationURI = uris.GenerateURIForAuthorization(
|
||||
username,
|
||||
intReq.ID,
|
||||
)
|
||||
intReq.AcceptedAt = testrig.TimeMustParse("2024-11-01T11:00:00+02:00")
|
||||
|
||||
if err := suite.state.DB.UpdateInteractionRequest(
|
||||
ctx,
|
||||
intReq,
|
||||
"response_uri",
|
||||
"authorization_uri",
|
||||
"accepted_at",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
testStatus.ApprovedByURI = intReq.AuthorizationURI
|
||||
if err := suite.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
testStatus,
|
||||
"approved_by_uri",
|
||||
); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
asStatus, err := suite.typeconverter.StatusToAS(ctx, testStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"sensitive": "as:sensitive"
|
||||
}
|
||||
],
|
||||
"approvedBy": "http://localhost:8080/users/1happyturtle/accepts/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"attachment": [],
|
||||
"attributedTo": "http://localhost:8080/users/admin",
|
||||
"cc": [
|
||||
"http://localhost:8080/users/admin/followers",
|
||||
"http://localhost:8080/users/1happyturtle"
|
||||
],
|
||||
"content": "\u003cp\u003eHi \u003cspan class=\"h-card\"\u003e\u003ca href=\"http://localhost:8080/@1happyturtle\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\"\u003e@\u003cspan\u003e1happyturtle\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, can I reply?\u003c/p\u003e",
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
"inReplyTo": "http://localhost:8080/users/1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
"interactionPolicy": {
|
||||
"canAnnounce": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canLike": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
},
|
||||
"canReply": {
|
||||
"always": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"approvalRequired": [],
|
||||
"automaticApproval": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"manualApproval": []
|
||||
}
|
||||
},
|
||||
"published": "2024-02-20T12:41:37+02:00",
|
||||
"replies": {
|
||||
"first": {
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true",
|
||||
"next": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies?page=true\u0026only_other_accounts=false",
|
||||
"partOf": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "CollectionPage"
|
||||
},
|
||||
"id": "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ/replies",
|
||||
"type": "Collection"
|
||||
},
|
||||
"replyAuthorization": "http://localhost:8080/users/1happyturtle/authorizations/01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"sensitive": false,
|
||||
"summary": "",
|
||||
"tag": {
|
||||
"href": "http://localhost:8080/users/1happyturtle",
|
||||
"name": "@1happyturtle@localhost:8080",
|
||||
"type": "Mention"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note",
|
||||
"url": "http://localhost:8080/@admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ"
|
||||
}`, string(bytes))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestStatusToASDeletePublicReply() {
|
||||
testStatus := suite.testStatuses["admin_account_status_3"]
|
||||
ctx := suite.T().Context()
|
||||
|
|
@ -1119,7 +1379,7 @@ func (suite *InternalToASTestSuite) TestSelfBoostFollowersOnlyToAS() {
|
|||
boostWrapperStatus.URI = "http://localhost:8080/users/the_mighty_zork/statuses/01G74JJ1KS331G2JXHRMZCE0ER"
|
||||
boostWrapperStatus.CreatedAt = testrig.TimeMustParse("2022-06-09T13:12:00Z")
|
||||
|
||||
asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus, testAccount, testAccount)
|
||||
asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asBoost)
|
||||
|
|
@ -1320,23 +1580,24 @@ func (suite *InternalToASTestSuite) TestPollVoteToASCreate() {
|
|||
}`, string(bytes1))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() {
|
||||
func (suite *InternalToASTestSuite) TestImpoliteInteractionReqToASAcceptAnnounce() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
CreatedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
StatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
Status: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
URI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K" + gtsmodel.AnnounceRequestSuffix,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionAnnounce,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
|
|
@ -1372,23 +1633,24 @@ func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptAnnounce() {
|
|||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLike() {
|
||||
func (suite *InternalToASTestSuite) TestImpoliteInteractionReqToASAcceptLike() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
CreatedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
StatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
Status: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
URI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K" + gtsmodel.LikeRequestSuffix,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(false),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
|
|
@ -1413,13 +1675,124 @@ func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLike() {
|
|||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"actor": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"object": "https://fossbros-anonymous.io/users/foss_satan/statuses/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"object": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"target": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"to": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"type": "Accept"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestInteractionReqToASAcceptLikePolite() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(true),
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AuthorizationURI: "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
accept, err := suite.typeconverter.InteractionReqToASAccept(
|
||||
suite.T().Context(),
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
i, err := ap.Serialize(accept)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(i, "", " ")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"actor": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"object": {
|
||||
"actor": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"id": "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"instrument": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"object": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"type": "LikeRequest"
|
||||
},
|
||||
"result": "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"to": "http://fossbros-anonymous.io/users/foss_satan",
|
||||
"type": "Accept"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestPoliteInteractionReqToASAuthorization() {
|
||||
acceptingAccount := suite.testAccounts["local_account_1"]
|
||||
interactingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
req := >smodel.InteractionRequest{
|
||||
ID: "01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
TargetStatusID: "01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
TargetStatus: >smodel.Status{URI: "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3"},
|
||||
TargetAccountID: acceptingAccount.ID,
|
||||
TargetAccount: acceptingAccount,
|
||||
InteractingAccountID: interactingAccount.ID,
|
||||
InteractingAccount: interactingAccount,
|
||||
InteractionURI: "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
InteractionType: gtsmodel.InteractionLike,
|
||||
Polite: util.Ptr(true),
|
||||
InteractionRequestURI: "https://fossbros-anonymous.io/users/foss_satan/interaction_requests/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
ResponseURI: "http://localhost:8080/users/the_mighty_zork/accepts/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AuthorizationURI: "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
AcceptedAt: testrig.TimeMustParse("2022-06-09T13:12:00Z"),
|
||||
}
|
||||
|
||||
auth, err := suite.typeconverter.InteractionReqToASAuthorization(
|
||||
suite.T().Context(),
|
||||
req,
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
i, err := ap.Serialize(auth)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(i, "", " ")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
suite.Equal(`{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"attributedTo": "http://localhost:8080/users/the_mighty_zork",
|
||||
"id": "http://localhost:8080/users/the_mighty_zork/authorizations/01J1AKMZ8JE5NW0ZSFTRC1JJNE",
|
||||
"interactingObject": "https://fossbros-anonymous.io/users/foss_satan/likes/01J1AKRRHQ6MDDQHV0TP716T2K",
|
||||
"interactionTarget": "http://localhost:8080/users/the_mighty_zork/statuses/01JJYCVKCXB9JTQD1XW2KB8MT3",
|
||||
"type": "LikeAuthorization"
|
||||
}`, string(b))
|
||||
}
|
||||
|
||||
func TestInternalToASTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(InternalToASTestSuite))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2883,7 +2883,7 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
|||
|
||||
interactedStatus, err := c.StatusToAPIStatus(
|
||||
ctx,
|
||||
req.Status,
|
||||
req.TargetStatus,
|
||||
requestingAcct,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -2921,16 +2921,21 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
|
|||
rejectedAt = util.FormatISO8601(req.RejectedAt)
|
||||
}
|
||||
|
||||
createdAt, err := id.TimeFromULID(req.ID)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting id to time: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apimodel.InteractionRequest{
|
||||
ID: req.ID,
|
||||
Type: req.InteractionType.String(),
|
||||
CreatedAt: util.FormatISO8601(req.CreatedAt),
|
||||
CreatedAt: util.FormatISO8601(createdAt),
|
||||
Account: interactingAcct,
|
||||
Status: interactedStatus,
|
||||
Reply: reply,
|
||||
AcceptedAt: acceptedAt,
|
||||
RejectedAt: rejectedAt,
|
||||
URI: req.URI,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3054,7 +3054,7 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
|
|||
suite.Equal(`{
|
||||
"id": "01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
"type": "reply",
|
||||
"created_at": "2024-02-20T10:41:37.000Z",
|
||||
"created_at": "2024-08-20T12:24:13.966Z",
|
||||
"account": {
|
||||
"id": "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
"username": "admin",
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func (c *Converter) WrapAccountableInUpdate(accountable ap.Accountable) (vocab.A
|
|||
update.SetActivityStreamsObject(objectProp)
|
||||
|
||||
// to should be public.
|
||||
ap.AppendTo(update, ap.PublicURI())
|
||||
ap.AppendTo(update, ap.PublicIRI())
|
||||
|
||||
// bcc should be followers.
|
||||
ap.AppendBcc(update, ap.GetFollowers(accountable))
|
||||
|
|
|
|||
|
|
@ -27,27 +27,28 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
UsersPath = "users" // UsersPath is for serving users info
|
||||
StatusesPath = "statuses" // StatusesPath is for serving statuses
|
||||
InboxPath = "inbox" // InboxPath represents the activitypub inbox location
|
||||
OutboxPath = "outbox" // OutboxPath represents the activitypub outbox location
|
||||
FollowersPath = "followers" // FollowersPath represents the activitypub followers location
|
||||
FollowingPath = "following" // FollowingPath represents the activitypub following location
|
||||
LikedPath = "liked" // LikedPath represents the activitypub liked location
|
||||
CollectionsPath = "collections" // CollectionsPath represents the activitypub collections location
|
||||
FeaturedPath = "featured" // FeaturedPath represents the activitypub featured location
|
||||
PublicKeyPath = "main-key" // PublicKeyPath is for serving an account's public key
|
||||
FollowPath = "follow" // FollowPath used to generate the URI for an individual follow or follow request
|
||||
UpdatePath = "updates" // UpdatePath is used to generate the URI for an account update
|
||||
BlocksPath = "blocks" // BlocksPath is used to generate the URI for a block
|
||||
MovesPath = "moves" // MovesPath is used to generate the URI for a move
|
||||
ReportsPath = "reports" // ReportsPath is used to generate the URI for a report/flag
|
||||
ConfirmEmailPath = "confirm_email" // ConfirmEmailPath is used to generate the URI for an email confirmation link
|
||||
FileserverPath = "fileserver" // FileserverPath is a path component for serving attachments + media
|
||||
EmojiPath = "emoji" // EmojiPath represents the activitypub emoji location
|
||||
TagsPath = "tags" // TagsPath represents the activitypub tags location
|
||||
AcceptsPath = "accepts" // AcceptsPath represents the activitypub Accept's location
|
||||
RejectsPath = "rejects" // RejectsPath represents the activitypub Reject's location
|
||||
UsersPath = "users" // UsersPath is for serving users info
|
||||
StatusesPath = "statuses" // StatusesPath is for serving statuses
|
||||
InboxPath = "inbox" // InboxPath represents the activitypub inbox location
|
||||
OutboxPath = "outbox" // OutboxPath represents the activitypub outbox location
|
||||
FollowersPath = "followers" // FollowersPath represents the activitypub followers location
|
||||
FollowingPath = "following" // FollowingPath represents the activitypub following location
|
||||
LikedPath = "liked" // LikedPath represents the activitypub liked location
|
||||
CollectionsPath = "collections" // CollectionsPath represents the activitypub collections location
|
||||
FeaturedPath = "featured" // FeaturedPath represents the activitypub featured location
|
||||
PublicKeyPath = "main-key" // PublicKeyPath is for serving an account's public key
|
||||
FollowPath = "follow" // FollowPath used to generate the URI for an individual follow or follow request
|
||||
UpdatePath = "updates" // UpdatePath is used to generate the URI for an account update
|
||||
BlocksPath = "blocks" // BlocksPath is used to generate the URI for a block
|
||||
MovesPath = "moves" // MovesPath is used to generate the URI for a move
|
||||
ReportsPath = "reports" // ReportsPath is used to generate the URI for a report/flag
|
||||
ConfirmEmailPath = "confirm_email" // ConfirmEmailPath is used to generate the URI for an email confirmation link
|
||||
FileserverPath = "fileserver" // FileserverPath is a path component for serving attachments + media
|
||||
EmojiPath = "emoji" // EmojiPath represents the activitypub emoji location
|
||||
TagsPath = "tags" // TagsPath represents the activitypub tags location
|
||||
AcceptsPath = "accepts" // AcceptsPath represents the activitypub Accept's location
|
||||
AuthorizationsPath = "authorizations" // AuthorizationsPath represents the location of an Authorization type such as LikeAuthorization, ReplyAuthorization, etc.
|
||||
RejectsPath = "rejects" // RejectsPath represents the activitypub Reject's location
|
||||
)
|
||||
|
||||
// UserURIs contains a bunch of UserURIs
|
||||
|
|
@ -210,6 +211,21 @@ func GenerateURIForAccept(username string, thisAcceptID string) string {
|
|||
)
|
||||
}
|
||||
|
||||
// GenerateURIForAuthorization returns the AP URI for a new Authorization object,
|
||||
// ie., LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization.
|
||||
// Eg., https://example.org/users/whatever_user/authorizations/01F7XTH1QGBAPMGF49WJZ91XGC
|
||||
func GenerateURIForAuthorization(username string, id string) string {
|
||||
proto := config.GetProtocol()
|
||||
host := config.GetHost()
|
||||
return buildURL4(proto,
|
||||
host,
|
||||
UsersPath,
|
||||
username,
|
||||
AuthorizationsPath,
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
// GenerateURIForReject returns the AP URI for a new Reject activity -- something like:
|
||||
// https://example.org/users/whatever_user/rejects/01F7XTH1QGBAPMGF49WJZ91XGC
|
||||
func GenerateURIForReject(username string, thisRejectID string) string {
|
||||
|
|
|
|||
|
|
@ -3360,21 +3360,20 @@ type ActivityWithSignature struct {
|
|||
// their requesting signatures.
|
||||
func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]ActivityWithSignature {
|
||||
dmForZork := NewAPNote(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6"),
|
||||
URLMustParse("http://fossbros-anonymous.io/@foss_satan/5424b153-4553-4f30-9358-7b92f7cd42f6"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"@the_mighty_zork@localhost:8080 hey zork here's a new private note for you",
|
||||
"new note for zork",
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
[]*url.URL{URLMustParse("http://localhost:8080/users/the_mighty_zork")},
|
||||
nil,
|
||||
true,
|
||||
[]vocab.ActivityStreamsMention{newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
)},
|
||||
[]vocab.TootHashtag{},
|
||||
nil,
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6"),
|
||||
URL: URLMustParse("http://fossbros-anonymous.io/@foss_satan/5424b153-4553-4f30-9358-7b92f7cd42f6"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "@the_mighty_zork@localhost:8080 hey zork here's a new private note for you",
|
||||
Summary: "new note for zork",
|
||||
AttributedTo: URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
To: []*url.URL{URLMustParse("http://localhost:8080/users/the_mighty_zork")},
|
||||
Sensitive: true,
|
||||
Mentions: []vocab.ActivityStreamsMention{newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
)},
|
||||
},
|
||||
)
|
||||
createDmForZork := WrapAPNoteInCreate(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6/activity"),
|
||||
|
|
@ -3384,21 +3383,19 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
|
|||
createDmForZorkSig, createDmForZorkDigest, creatDmForZorkDate := GetSignatureForActivity(createDmForZork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI))
|
||||
|
||||
replyToTurtle := NewAPNote(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"),
|
||||
URLMustParse("http://fossbros-anonymous.io/@foss_satan/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"@1happyturtle@localhost:8080 u suck lol",
|
||||
"",
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
[]*url.URL{URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")},
|
||||
[]*url.URL{URLMustParse("http://localhost:8080/users/1happyturtle")},
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/1happyturtle"),
|
||||
"@1happyturtle@localhost:8080",
|
||||
)},
|
||||
[]vocab.TootHashtag{},
|
||||
nil,
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"),
|
||||
URL: URLMustParse("http://fossbros-anonymous.io/@foss_satan/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "@1happyturtle@localhost:8080 u suck lol",
|
||||
AttributedTo: URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
To: []*url.URL{URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")},
|
||||
CC: []*url.URL{URLMustParse("http://localhost:8080/users/1happyturtle")},
|
||||
Mentions: []vocab.ActivityStreamsMention{newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/1happyturtle"),
|
||||
"@1happyturtle@localhost:8080",
|
||||
)},
|
||||
},
|
||||
)
|
||||
createReplyToTurtle := WrapAPNoteInCreate(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"),
|
||||
|
|
@ -3409,23 +3406,20 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
|
|||
createReplyToTurtleForTurtleSig, createReplyToTurtleForTurtleDigest, createReplyToTurtleForTurtleDate := GetSignatureForActivity(createReplyToTurtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_2"].InboxURI))
|
||||
|
||||
forwardedMessage := NewAPNote(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"this is a public status, please forward it!",
|
||||
"",
|
||||
URLMustParse("http://example.org/users/Some_User"),
|
||||
[]*url.URL{ap.PublicURI()},
|
||||
nil,
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{},
|
||||
[]vocab.TootHashtag{},
|
||||
[]vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
|
||||
"image/jpeg",
|
||||
"trent reznor looking handsome as balls",
|
||||
"LEDara58O=t5EMSOENEN9]}?aK%0"),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
URL: URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "this is a public status, please forward it!",
|
||||
AttributedTo: URLMustParse("http://example.org/users/Some_User"),
|
||||
To: []*url.URL{ap.PublicIRI()},
|
||||
Attachments: []vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
|
||||
"image/jpeg",
|
||||
"trent reznor looking handsome as balls",
|
||||
"LEDara58O=t5EMSOENEN9]}?aK%0"),
|
||||
},
|
||||
},
|
||||
)
|
||||
createForwardedMessage := WrapAPNoteInCreate(
|
||||
|
|
@ -3473,33 +3467,33 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
|
|||
deleteForRemoteAccount3Sig, deleteForRemoteAccount3Digest, deleteForRemoteAccount3Date := GetSignatureForActivity(deleteForRemoteAccount3, "https://somewhere.mysterious/users/rest_in_piss#main-key", keyToSignDelete, URLMustParse(accounts["local_account_1"].InboxURI))
|
||||
|
||||
remoteAccount2Status1Updated := NewAPNote(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/01HE7XJ1CG84TBKH5V9XKBVGF5"),
|
||||
URLMustParse("http://example.org/@Some_User/statuses/01HE7XJ1CG84TBKH5V9XKBVGF5"),
|
||||
TimeMustParse("2023-11-02T12:44:25+02:00"),
|
||||
`<p>hi <span class="h-card"><a href="http://localhost:8080/@admin" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>admin</span></a></span> here's some media for ya, <span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>the_mighty_zork</span></a></span> you might like this too</p>`,
|
||||
"<p>some unknown media included</p>",
|
||||
URLMustParse("http://example.org/users/Some_User"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{
|
||||
URLMustParse("http://example.org/users/Some_User/followers"),
|
||||
URLMustParse("http://localhost:8080/users/admin"),
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
},
|
||||
true,
|
||||
[]vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://example.org/users/Some_User/statuses/01HE7XJ1CG84TBKH5V9XKBVGF5"),
|
||||
URL: URLMustParse("http://example.org/@Some_User/statuses/01HE7XJ1CG84TBKH5V9XKBVGF5"),
|
||||
CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"),
|
||||
Content: `<p>hi <span class="h-card"><a href="http://localhost:8080/@admin" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>admin</span></a></span> here's some media for ya, <span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>the_mighty_zork</span></a></span> you might like this too</p>`,
|
||||
Summary: "<p>some unknown media included</p>",
|
||||
AttributedTo: URLMustParse("http://example.org/users/Some_User"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
},
|
||||
CC: []*url.URL{
|
||||
URLMustParse("http://example.org/users/Some_User/followers"),
|
||||
URLMustParse("http://localhost:8080/users/admin"),
|
||||
"@admin@localhost:8080",
|
||||
),
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
Sensitive: true,
|
||||
Mentions: []vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/admin"),
|
||||
"@admin@localhost:8080",
|
||||
),
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
update := WrapAPNoteInUpdate(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/01HE7XJ1CG84TBKH5V9XKBVGF5/update1"),
|
||||
|
|
@ -3849,126 +3843,114 @@ func NewTestFediAttachments(relativePath string) map[string]RemoteAttachmentFile
|
|||
func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
||||
return map[string]vocab.ActivityStreamsNote{
|
||||
"http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1": NewAPNote(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"this is a public status, please forward it!",
|
||||
"",
|
||||
URLMustParse("http://example.org/users/Some_User"),
|
||||
[]*url.URL{ap.PublicURI()},
|
||||
nil,
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{},
|
||||
[]vocab.TootHashtag{},
|
||||
[]vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
|
||||
"image/jpeg",
|
||||
"trent reznor looking handsome as balls",
|
||||
"LEDara58O=t5EMSOENEN9]}?aK%0"),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
URL: URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "this is a public status, please forward it!",
|
||||
AttributedTo: URLMustParse("http://example.org/users/Some_User"),
|
||||
To: []*url.URL{ap.PublicIRI()},
|
||||
Attachments: []vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
|
||||
"image/jpeg",
|
||||
"trent reznor looking handsome as balls",
|
||||
"LEDara58O=t5EMSOENEN9]}?aK%0"),
|
||||
},
|
||||
},
|
||||
),
|
||||
"https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839": NewAPNote(
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839"),
|
||||
URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"Hello world!",
|
||||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839"),
|
||||
URL: URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "Hello world!",
|
||||
AttributedTo: URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
},
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
nil,
|
||||
[]vocab.TootHashtag{},
|
||||
nil,
|
||||
),
|
||||
"https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV": NewAPNote(
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV"),
|
||||
URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"Hey @the_mighty_zork@localhost:8080 how's it going?",
|
||||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV"),
|
||||
URL: URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: "Hey @the_mighty_zork@localhost:8080 how's it going?",
|
||||
AttributedTo: URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
},
|
||||
Mentions: []vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
[]vocab.TootHashtag{},
|
||||
nil,
|
||||
),
|
||||
"https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7": NewAPNote(
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"),
|
||||
URLMustParse("https://unknown-instance.com/users/@brand_new_person/01H641QSRS3TCXSVC10X4GPKW7"),
|
||||
TimeMustParse("2023-04-12T12:13:12+02:00"),
|
||||
"<p>Babe are you okay, you've hardly touched your <a href=\"https://unknown-instance.com/tags/piss\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>piss</span></a></p>",
|
||||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"),
|
||||
URL: URLMustParse("https://unknown-instance.com/users/@brand_new_person/01H641QSRS3TCXSVC10X4GPKW7"),
|
||||
CreatedAt: TimeMustParse("2023-04-12T12:13:12+02:00"),
|
||||
Content: `<p><span class="h-card"><a href="http://fossbros-anonymous.io/@foss_satan" class="u-url mention">@<span>foss_satan</span></a></span>Babe are you okay, you've hardly touched your <a href="https://unknown-instance.com/tags/piss" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>piss</span></a></p>`,
|
||||
AttributedTo: URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
},
|
||||
Mentions: []vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
"@foss_satan@fossbros-anonymous.io",
|
||||
),
|
||||
},
|
||||
Tags: []vocab.TootHashtag{
|
||||
newAPHashtag(
|
||||
URLMustParse("https://unknown-instance.com/tags/piss"),
|
||||
"#piss",
|
||||
),
|
||||
},
|
||||
InReplyTo: URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/01FVW7JHQFSFK166WWKR8CBA6M"),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{},
|
||||
[]vocab.TootHashtag{
|
||||
newAPHashtag(
|
||||
URLMustParse("https://unknown-instance.com/tags/piss"),
|
||||
"#piss",
|
||||
),
|
||||
},
|
||||
nil,
|
||||
),
|
||||
"https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042": NewAPNote(
|
||||
URLMustParse("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042"),
|
||||
URLMustParse("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
"",
|
||||
"",
|
||||
URLMustParse("https://turnip.farm/users/turniplover6969"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
nil,
|
||||
[]vocab.TootHashtag{},
|
||||
[]vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg"),
|
||||
"image/jpeg",
|
||||
"",
|
||||
"",
|
||||
),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042"),
|
||||
URL: URLMustParse("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
AttributedTo: URLMustParse("https://turnip.farm/users/turniplover6969"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
},
|
||||
Attachments: []vocab.ActivityStreamsImage{
|
||||
newAPImage(
|
||||
URLMustParse("https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg"),
|
||||
"image/jpeg",
|
||||
"",
|
||||
"",
|
||||
),
|
||||
},
|
||||
},
|
||||
),
|
||||
"http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552": NewAPNote(
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552"),
|
||||
URLMustParse("http://fossbros-anonymous.io/@foss_satan/106221634728637552"),
|
||||
TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
`<p><span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention">@<span>the_mighty_zork</span></a></span> nice there it is:</p><p><a href="http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/activity" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">social.pixie.town/users/f0x/st</span><span class="invisible">atuses/106221628567855262/activity</span></a></p>`,
|
||||
"",
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
[]*url.URL{
|
||||
ap.PublicURI(),
|
||||
&NewAPNoteParams{
|
||||
ID: URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552"),
|
||||
URL: URLMustParse("http://fossbros-anonymous.io/@foss_satan/106221634728637552"),
|
||||
CreatedAt: TimeMustParse("2022-07-13T12:13:12+02:00"),
|
||||
Content: `<p><span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention">@<span>the_mighty_zork</span></a></span> nice there it is:</p><p><a href="http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/activity" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">social.pixie.town/users/f0x/st</span><span class="invisible">atuses/106221628567855262/activity</span></a></p>`,
|
||||
AttributedTo: URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
To: []*url.URL{
|
||||
ap.PublicIRI(),
|
||||
},
|
||||
Mentions: []vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{
|
||||
newAPMention(
|
||||
URLMustParse("http://localhost:8080/users/the_mighty_zork"),
|
||||
"@the_mighty_zork@localhost:8080",
|
||||
),
|
||||
},
|
||||
[]vocab.TootHashtag{},
|
||||
nil,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -4235,14 +4217,21 @@ func NewTestWebPushSubscriptions() map[string]*gtsmodel.WebPushSubscription {
|
|||
|
||||
func NewTestInteractionRequests() map[string]*gtsmodel.InteractionRequest {
|
||||
return map[string]*gtsmodel.InteractionRequest{
|
||||
// Impolite reply request.
|
||||
//
|
||||
// TODO: in v0.21.0 change this to a polite
|
||||
// reply request, as this is a local interaction
|
||||
// request, and polite is the only kind we'll
|
||||
// be sending out *ourselves* from then on.
|
||||
"admin_account_reply_turtle": {
|
||||
ID: "01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
CreatedAt: TimeMustParse("2024-02-20T12:41:37+02:00"),
|
||||
StatusID: "01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
||||
InteractingAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
InteractionURI: "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
ID: "01J5QVXCCEATJYSXM9H6MZT4JR",
|
||||
TargetStatusID: "01F8MHC8VWDRBQR0N1BATDDEM5",
|
||||
TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
||||
InteractingAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
InteractionURI: "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ",
|
||||
InteractionRequestURI: "http://localhost:8080/users/admin/statuses/01J5QVB9VC76NPPRQ207GG4DRZ#ReplyRequest",
|
||||
InteractionType: gtsmodel.InteractionReply,
|
||||
Polite: util.Ptr(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -5080,99 +5069,103 @@ func newAPEmoji(id *url.URL, name string, updated time.Time, image vocab.Activit
|
|||
return emoji
|
||||
}
|
||||
|
||||
// NewAPNote returns a new activity streams note for the given parameters
|
||||
func NewAPNote(
|
||||
noteID *url.URL,
|
||||
noteURL *url.URL,
|
||||
noteCreatedAt time.Time,
|
||||
noteContent string,
|
||||
noteSummary string,
|
||||
noteAttributedTo *url.URL,
|
||||
noteTo []*url.URL,
|
||||
noteCC []*url.URL,
|
||||
noteSensitive bool,
|
||||
noteMentions []vocab.ActivityStreamsMention,
|
||||
noteTags []vocab.TootHashtag,
|
||||
noteAttachments []vocab.ActivityStreamsImage,
|
||||
) vocab.ActivityStreamsNote {
|
||||
// create the note itself
|
||||
type NewAPNoteParams struct {
|
||||
ID *url.URL
|
||||
URL *url.URL
|
||||
CreatedAt time.Time
|
||||
Content string
|
||||
Summary string
|
||||
AttributedTo *url.URL
|
||||
To []*url.URL
|
||||
CC []*url.URL
|
||||
Sensitive bool
|
||||
Mentions []vocab.ActivityStreamsMention
|
||||
Tags []vocab.TootHashtag
|
||||
Attachments []vocab.ActivityStreamsImage
|
||||
InReplyTo *url.URL
|
||||
ApprovedBy *url.URL
|
||||
ReplyAuthorization *url.URL
|
||||
}
|
||||
|
||||
// NewAPNote is a utility function that returns a new
|
||||
// activity streams note using the given parameters.
|
||||
func NewAPNote(p *NewAPNoteParams) vocab.ActivityStreamsNote {
|
||||
// Instantiate the note itself.
|
||||
note := streams.NewActivityStreamsNote()
|
||||
|
||||
// set id
|
||||
if noteID != nil {
|
||||
id := streams.NewJSONLDIdProperty()
|
||||
id.Set(noteID)
|
||||
note.SetJSONLDId(id)
|
||||
// Set id.
|
||||
if p.ID != nil {
|
||||
ap.SetJSONLDId(note, p.ID)
|
||||
}
|
||||
|
||||
// set noteURL
|
||||
if noteURL != nil {
|
||||
url := streams.NewActivityStreamsUrlProperty()
|
||||
url.AppendIRI(noteURL)
|
||||
note.SetActivityStreamsUrl(url)
|
||||
// Set noteURL.
|
||||
if p.URL != nil {
|
||||
ap.AppendURL(note, p.URL)
|
||||
}
|
||||
|
||||
published := streams.NewActivityStreamsPublishedProperty()
|
||||
published.Set(noteCreatedAt)
|
||||
note.SetActivityStreamsPublished(published)
|
||||
// Set published.
|
||||
ap.SetPublished(note, p.CreatedAt)
|
||||
|
||||
// set noteContent
|
||||
if noteContent != "" {
|
||||
content := streams.NewActivityStreamsContentProperty()
|
||||
content.AppendXMLSchemaString(noteContent)
|
||||
note.SetActivityStreamsContent(content)
|
||||
// Set content.
|
||||
if p.Content != "" {
|
||||
ap.AppendContent(note, p.Content)
|
||||
}
|
||||
|
||||
// set noteSummary (aka content warning)
|
||||
if noteSummary != "" {
|
||||
summary := streams.NewActivityStreamsSummaryProperty()
|
||||
summary.AppendXMLSchemaString(noteSummary)
|
||||
note.SetActivityStreamsSummary(summary)
|
||||
// Set summary (aka content warning).
|
||||
if p.Summary != "" {
|
||||
ap.AppendSummary(note, p.Summary)
|
||||
}
|
||||
|
||||
// set noteAttributedTo (the url of the author of the note)
|
||||
if noteAttributedTo != nil {
|
||||
attributedTo := streams.NewActivityStreamsAttributedToProperty()
|
||||
attributedTo.AppendIRI(noteAttributedTo)
|
||||
note.SetActivityStreamsAttributedTo(attributedTo)
|
||||
// Set attributedTo (ie., the
|
||||
// uri of the author of the note).
|
||||
if p.AttributedTo != nil {
|
||||
ap.AppendAttributedTo(note, p.AttributedTo)
|
||||
}
|
||||
|
||||
// set noteTO
|
||||
if noteTo != nil {
|
||||
to := streams.NewActivityStreamsToProperty()
|
||||
for _, r := range noteTo {
|
||||
to.AppendIRI(r)
|
||||
}
|
||||
note.SetActivityStreamsTo(to)
|
||||
// Set `to`.
|
||||
if p.To != nil {
|
||||
ap.AppendTo(note, p.To...)
|
||||
}
|
||||
|
||||
// set noteCC
|
||||
if noteCC != nil {
|
||||
cc := streams.NewActivityStreamsCcProperty()
|
||||
for _, r := range noteCC {
|
||||
cc.AppendIRI(r)
|
||||
}
|
||||
note.SetActivityStreamsCc(cc)
|
||||
// Set `cc`.
|
||||
if p.CC != nil {
|
||||
ap.AppendCc(note, p.CC...)
|
||||
}
|
||||
|
||||
// Set `inReplyTo`.
|
||||
if p.InReplyTo != nil {
|
||||
ap.AppendInReplyTo(note, p.InReplyTo)
|
||||
}
|
||||
|
||||
// Set `approvedBy`.
|
||||
if p.ApprovedBy != nil {
|
||||
ap.SetApprovedBy(note, p.ApprovedBy)
|
||||
}
|
||||
|
||||
// Set `replyAuthorization`.
|
||||
if p.ReplyAuthorization != nil {
|
||||
ap.SetReplyAuthorization(note, p.ReplyAuthorization)
|
||||
}
|
||||
|
||||
// Tag entries
|
||||
tag := streams.NewActivityStreamsTagProperty()
|
||||
|
||||
// mentions
|
||||
for _, m := range noteMentions {
|
||||
// Set mentions.
|
||||
for _, m := range p.Mentions {
|
||||
tag.AppendActivityStreamsMention(m)
|
||||
}
|
||||
note.SetActivityStreamsTag(tag)
|
||||
|
||||
// hashtags
|
||||
for _, t := range noteTags {
|
||||
// Set hashtags.
|
||||
for _, t := range p.Tags {
|
||||
tag.AppendTootHashtag(t)
|
||||
}
|
||||
|
||||
// append any attachments as ActivityStreamsImage
|
||||
if noteAttachments != nil {
|
||||
// Append any attachments
|
||||
// as ActivityStreamsImage
|
||||
if p.Attachments != nil {
|
||||
attachmentProperty := streams.NewActivityStreamsAttachmentProperty()
|
||||
for _, a := range noteAttachments {
|
||||
for _, a := range p.Attachments {
|
||||
attachmentProperty.AppendActivityStreamsImage(a)
|
||||
}
|
||||
note.SetActivityStreamsAttachment(attachmentProperty)
|
||||
|
|
|
|||
9
vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go
generated
vendored
9
vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go
generated
vendored
|
|
@ -254,6 +254,9 @@ var ActivityStreamsAltitudePropertyName string = "altitude"
|
|||
// GoToSocialAlwaysPropertyName is the string literal of the name for the always property in the GoToSocial vocabulary.
|
||||
var GoToSocialAlwaysPropertyName string = "always"
|
||||
|
||||
// GoToSocialAnnounceAuthorizationPropertyName is the string literal of the name for the announceAuthorization property in the GoToSocial vocabulary.
|
||||
var GoToSocialAnnounceAuthorizationPropertyName string = "announceAuthorization"
|
||||
|
||||
// ActivityStreamsAnyOfPropertyName is the string literal of the name for the anyOf property in the ActivityStreams vocabulary.
|
||||
var ActivityStreamsAnyOfPropertyName string = "anyOf"
|
||||
|
||||
|
|
@ -404,6 +407,9 @@ var ActivityStreamsLastPropertyName string = "last"
|
|||
// ActivityStreamsLatitudePropertyName is the string literal of the name for the latitude property in the ActivityStreams vocabulary.
|
||||
var ActivityStreamsLatitudePropertyName string = "latitude"
|
||||
|
||||
// GoToSocialLikeAuthorizationPropertyName is the string literal of the name for the likeAuthorization property in the GoToSocial vocabulary.
|
||||
var GoToSocialLikeAuthorizationPropertyName string = "likeAuthorization"
|
||||
|
||||
// ActivityStreamsLikedPropertyName is the string literal of the name for the liked property in the ActivityStreams vocabulary.
|
||||
var ActivityStreamsLikedPropertyName string = "liked"
|
||||
|
||||
|
|
@ -491,6 +497,9 @@ var ActivityStreamsRelationshipPropertyName string = "relationship"
|
|||
// ActivityStreamsRepliesPropertyName is the string literal of the name for the replies property in the ActivityStreams vocabulary.
|
||||
var ActivityStreamsRepliesPropertyName string = "replies"
|
||||
|
||||
// GoToSocialReplyAuthorizationPropertyName is the string literal of the name for the replyAuthorization property in the GoToSocial vocabulary.
|
||||
var GoToSocialReplyAuthorizationPropertyName string = "replyAuthorization"
|
||||
|
||||
// ActivityStreamsResultPropertyName is the string literal of the name for the result property in the ActivityStreams vocabulary.
|
||||
var ActivityStreamsResultPropertyName string = "result"
|
||||
|
||||
|
|
|
|||
6
vendor/code.superseriousbusiness.org/activity/streams/gen_init.go
generated
vendored
6
vendor/code.superseriousbusiness.org/activity/streams/gen_init.go
generated
vendored
|
|
@ -140,6 +140,7 @@ import (
|
|||
typelibrary "code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_library"
|
||||
typetrack "code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_track"
|
||||
propertyalways "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_always"
|
||||
propertyannounceauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization"
|
||||
propertyapprovalrequired "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvalrequired"
|
||||
propertyapprovedby "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvedby"
|
||||
propertyautomaticapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_automaticapproval"
|
||||
|
|
@ -152,7 +153,9 @@ import (
|
|||
propertyinteractingobject "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactingobject"
|
||||
propertyinteractionpolicy "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactionpolicy"
|
||||
propertyinteractiontarget "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactiontarget"
|
||||
propertylikeauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization"
|
||||
propertymanualapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_manualapproval"
|
||||
propertyreplyauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization"
|
||||
typeannounceapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceapproval"
|
||||
typeannounceauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceauthorization"
|
||||
typeannouncerequest "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announcerequest"
|
||||
|
|
@ -337,6 +340,7 @@ func init() {
|
|||
typelibrary.SetManager(mgr)
|
||||
typetrack.SetManager(mgr)
|
||||
propertyalways.SetManager(mgr)
|
||||
propertyannounceauthorization.SetManager(mgr)
|
||||
propertyapprovalrequired.SetManager(mgr)
|
||||
propertyapprovedby.SetManager(mgr)
|
||||
propertyautomaticapproval.SetManager(mgr)
|
||||
|
|
@ -349,7 +353,9 @@ func init() {
|
|||
propertyinteractingobject.SetManager(mgr)
|
||||
propertyinteractionpolicy.SetManager(mgr)
|
||||
propertyinteractiontarget.SetManager(mgr)
|
||||
propertylikeauthorization.SetManager(mgr)
|
||||
propertymanualapproval.SetManager(mgr)
|
||||
propertyreplyauthorization.SetManager(mgr)
|
||||
typeannounceapproval.SetManager(mgr)
|
||||
typeannounceauthorization.SetManager(mgr)
|
||||
typeannouncerequest.SetManager(mgr)
|
||||
|
|
|
|||
42
vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go
generated
vendored
42
vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go
generated
vendored
|
|
@ -140,6 +140,7 @@ import (
|
|||
typelibrary "code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_library"
|
||||
typetrack "code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_track"
|
||||
propertyalways "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_always"
|
||||
propertyannounceauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization"
|
||||
propertyapprovalrequired "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvalrequired"
|
||||
propertyapprovedby "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvedby"
|
||||
propertyautomaticapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_automaticapproval"
|
||||
|
|
@ -152,7 +153,9 @@ import (
|
|||
propertyinteractingobject "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactingobject"
|
||||
propertyinteractionpolicy "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactionpolicy"
|
||||
propertyinteractiontarget "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactiontarget"
|
||||
propertylikeauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization"
|
||||
propertymanualapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_manualapproval"
|
||||
propertyreplyauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization"
|
||||
typeannounceapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceapproval"
|
||||
typeannounceauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceauthorization"
|
||||
typeannouncerequest "code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announcerequest"
|
||||
|
|
@ -351,6 +354,19 @@ func (this Manager) DeserializeAnnounceAuthorizationGoToSocial() func(map[string
|
|||
}
|
||||
}
|
||||
|
||||
// DeserializeAnnounceAuthorizationPropertyGoToSocial returns the deserialization
|
||||
// method for the "GoToSocialAnnounceAuthorizationProperty" non-functional
|
||||
// property in the vocabulary "GoToSocial"
|
||||
func (this Manager) DeserializeAnnounceAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialAnnounceAuthorizationProperty, error) {
|
||||
return func(m map[string]interface{}, aliasMap map[string]string) (vocab.GoToSocialAnnounceAuthorizationProperty, error) {
|
||||
i, err := propertyannounceauthorization.DeserializeAnnounceAuthorizationProperty(m, aliasMap)
|
||||
if i == nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
// DeserializeAnnounceRequestGoToSocial returns the deserialization method for the
|
||||
// "GoToSocialAnnounceRequest" non-functional property in the vocabulary
|
||||
// "GoToSocial"
|
||||
|
|
@ -1469,6 +1485,19 @@ func (this Manager) DeserializeLikeAuthorizationGoToSocial() func(map[string]int
|
|||
}
|
||||
}
|
||||
|
||||
// DeserializeLikeAuthorizationPropertyGoToSocial returns the deserialization
|
||||
// method for the "GoToSocialLikeAuthorizationProperty" non-functional
|
||||
// property in the vocabulary "GoToSocial"
|
||||
func (this Manager) DeserializeLikeAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialLikeAuthorizationProperty, error) {
|
||||
return func(m map[string]interface{}, aliasMap map[string]string) (vocab.GoToSocialLikeAuthorizationProperty, error) {
|
||||
i, err := propertylikeauthorization.DeserializeLikeAuthorizationProperty(m, aliasMap)
|
||||
if i == nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
// DeserializeLikeRequestGoToSocial returns the deserialization method for the
|
||||
// "GoToSocialLikeRequest" non-functional property in the vocabulary
|
||||
// "GoToSocial"
|
||||
|
|
@ -2132,6 +2161,19 @@ func (this Manager) DeserializeReplyAuthorizationGoToSocial() func(map[string]in
|
|||
}
|
||||
}
|
||||
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the deserialization
|
||||
// method for the "GoToSocialReplyAuthorizationProperty" non-functional
|
||||
// property in the vocabulary "GoToSocial"
|
||||
func (this Manager) DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error) {
|
||||
return func(m map[string]interface{}, aliasMap map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error) {
|
||||
i, err := propertyreplyauthorization.DeserializeReplyAuthorizationProperty(m, aliasMap)
|
||||
if i == nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
// DeserializeReplyRequestGoToSocial returns the deserialization method for the
|
||||
// "GoToSocialReplyRequest" non-functional property in the vocabulary
|
||||
// "GoToSocial"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package streams
|
|||
|
||||
import (
|
||||
propertyalways "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_always"
|
||||
propertyannounceauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization"
|
||||
propertyapprovalrequired "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvalrequired"
|
||||
propertyapprovedby "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvedby"
|
||||
propertyautomaticapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_automaticapproval"
|
||||
|
|
@ -16,7 +17,9 @@ import (
|
|||
propertyinteractingobject "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactingobject"
|
||||
propertyinteractionpolicy "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactionpolicy"
|
||||
propertyinteractiontarget "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactiontarget"
|
||||
propertylikeauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization"
|
||||
propertymanualapproval "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_manualapproval"
|
||||
propertyreplyauthorization "code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization"
|
||||
vocab "code.superseriousbusiness.org/activity/streams/vocab"
|
||||
)
|
||||
|
||||
|
|
@ -25,6 +28,12 @@ func NewGoToSocialAlwaysProperty() vocab.GoToSocialAlwaysProperty {
|
|||
return propertyalways.NewGoToSocialAlwaysProperty()
|
||||
}
|
||||
|
||||
// NewGoToSocialGoToSocialAnnounceAuthorizationProperty creates a new
|
||||
// GoToSocialAnnounceAuthorizationProperty
|
||||
func NewGoToSocialAnnounceAuthorizationProperty() vocab.GoToSocialAnnounceAuthorizationProperty {
|
||||
return propertyannounceauthorization.NewGoToSocialAnnounceAuthorizationProperty()
|
||||
}
|
||||
|
||||
// NewGoToSocialGoToSocialApprovalRequiredProperty creates a new
|
||||
// GoToSocialApprovalRequiredProperty
|
||||
func NewGoToSocialApprovalRequiredProperty() vocab.GoToSocialApprovalRequiredProperty {
|
||||
|
|
@ -94,8 +103,20 @@ func NewGoToSocialInteractionTargetProperty() vocab.GoToSocialInteractionTargetP
|
|||
return propertyinteractiontarget.NewGoToSocialInteractionTargetProperty()
|
||||
}
|
||||
|
||||
// NewGoToSocialGoToSocialLikeAuthorizationProperty creates a new
|
||||
// GoToSocialLikeAuthorizationProperty
|
||||
func NewGoToSocialLikeAuthorizationProperty() vocab.GoToSocialLikeAuthorizationProperty {
|
||||
return propertylikeauthorization.NewGoToSocialLikeAuthorizationProperty()
|
||||
}
|
||||
|
||||
// NewGoToSocialGoToSocialManualApprovalProperty creates a new
|
||||
// GoToSocialManualApprovalProperty
|
||||
func NewGoToSocialManualApprovalProperty() vocab.GoToSocialManualApprovalProperty {
|
||||
return propertymanualapproval.NewGoToSocialManualApprovalProperty()
|
||||
}
|
||||
|
||||
// NewGoToSocialGoToSocialReplyAuthorizationProperty creates a new
|
||||
// GoToSocialReplyAuthorizationProperty
|
||||
func NewGoToSocialReplyAuthorizationProperty() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return propertyreplyauthorization.NewGoToSocialReplyAuthorizationProperty()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsAltitudeProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeAltitudePropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsAltitudeProperty, error)
|
||||
// DeserializeAnnounceAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialAnnounceAuthorizationProperty" non-functional property
|
||||
// in the vocabulary "GoToSocial"
|
||||
DeserializeAnnounceAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialAnnounceAuthorizationProperty, error)
|
||||
// DeserializeApprovedByPropertyGoToSocial returns the deserialization
|
||||
// method for the "GoToSocialApprovedByProperty" non-functional
|
||||
// property in the vocabulary "GoToSocial"
|
||||
|
|
|
|||
|
|
@ -31,48 +31,49 @@ import (
|
|||
// "type": "Announce"
|
||||
// }
|
||||
type ActivityStreamsAnnounce struct {
|
||||
ActivityStreamsActor vocab.ActivityStreamsActorProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
ActivityStreamsInstrument vocab.ActivityStreamsInstrumentProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsOrigin vocab.ActivityStreamsOriginProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsResult vocab.ActivityStreamsResultProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTarget vocab.ActivityStreamsTargetProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsActor vocab.ActivityStreamsActorProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialAnnounceAuthorization vocab.GoToSocialAnnounceAuthorizationProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
ActivityStreamsInstrument vocab.ActivityStreamsInstrumentProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsOrigin vocab.ActivityStreamsOriginProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsResult vocab.ActivityStreamsResultProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTarget vocab.ActivityStreamsTargetProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsAnnounceExtends returns true if the Announce type extends from
|
||||
|
|
@ -154,6 +155,11 @@ func DeserializeAnnounce(m map[string]interface{}, aliasMap map[string]string) (
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsAltitude = p
|
||||
}
|
||||
if p, err := mgr.DeserializeAnnounceAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialAnnounceAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeApprovedByPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -353,6 +359,8 @@ func DeserializeAnnounce(m map[string]interface{}, aliasMap map[string]string) (
|
|||
continue
|
||||
} else if k == "altitude" {
|
||||
continue
|
||||
} else if k == "announceAuthorization" {
|
||||
continue
|
||||
} else if k == "approvedBy" {
|
||||
continue
|
||||
} else if k == "attachment" {
|
||||
|
|
@ -684,6 +692,12 @@ func (this ActivityStreamsAnnounce) GetActivityStreamsUrl() vocab.ActivityStream
|
|||
return this.ActivityStreamsUrl
|
||||
}
|
||||
|
||||
// GetGoToSocialAnnounceAuthorization returns the "announceAuthorization" property
|
||||
// if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsAnnounce) GetGoToSocialAnnounceAuthorization() vocab.GoToSocialAnnounceAuthorizationProperty {
|
||||
return this.GoToSocialAnnounceAuthorization
|
||||
}
|
||||
|
||||
// GetGoToSocialApprovedBy returns the "approvedBy" property if it exists, and nil
|
||||
// otherwise.
|
||||
func (this ActivityStreamsAnnounce) GetGoToSocialApprovedBy() vocab.GoToSocialApprovedByProperty {
|
||||
|
|
@ -727,6 +741,7 @@ func (this ActivityStreamsAnnounce) JSONLDContext() map[string]string {
|
|||
m := map[string]string{"https://www.w3.org/ns/activitystreams": this.alias}
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsActor, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsAltitude, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialAnnounceAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialApprovedBy, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsAttachment, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsAttributedTo, m)
|
||||
|
|
@ -801,6 +816,20 @@ func (this ActivityStreamsAnnounce) LessThan(o vocab.ActivityStreamsAnnounce) bo
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "announceAuthorization"
|
||||
if lhs, rhs := this.GoToSocialAnnounceAuthorization, o.GetGoToSocialAnnounceAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "approvedBy"
|
||||
if lhs, rhs := this.GoToSocialApprovedBy, o.GetGoToSocialApprovedBy(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1372,6 +1401,14 @@ func (this ActivityStreamsAnnounce) Serialize() (map[string]interface{}, error)
|
|||
m[this.ActivityStreamsAltitude.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "announceAuthorization"
|
||||
if this.GoToSocialAnnounceAuthorization != nil {
|
||||
if i, err := this.GoToSocialAnnounceAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialAnnounceAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "approvedBy"
|
||||
if this.GoToSocialApprovedBy != nil {
|
||||
if i, err := this.GoToSocialApprovedBy.Serialize(); err != nil {
|
||||
|
|
@ -1875,6 +1912,11 @@ func (this *ActivityStreamsAnnounce) SetActivityStreamsUrl(i vocab.ActivityStrea
|
|||
this.ActivityStreamsUrl = i
|
||||
}
|
||||
|
||||
// SetGoToSocialAnnounceAuthorization sets the "announceAuthorization" property.
|
||||
func (this *ActivityStreamsAnnounce) SetGoToSocialAnnounceAuthorization(i vocab.GoToSocialAnnounceAuthorizationProperty) {
|
||||
this.GoToSocialAnnounceAuthorization = i
|
||||
}
|
||||
|
||||
// SetGoToSocialApprovedBy sets the "approvedBy" property.
|
||||
func (this *ActivityStreamsAnnounce) SetGoToSocialApprovedBy(i vocab.GoToSocialApprovedByProperty) {
|
||||
this.GoToSocialApprovedBy = i
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -22,44 +22,45 @@ import (
|
|||
// "type": "Article"
|
||||
// }
|
||||
type ActivityStreamsArticle struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsArticleExtends returns true if the Article type extends from the
|
||||
|
|
@ -261,6 +262,11 @@ func DeserializeArticle(m map[string]interface{}, aliasMap map[string]string) (*
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -372,6 +378,8 @@ func DeserializeArticle(m map[string]interface{}, aliasMap map[string]string) (*
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -625,6 +633,12 @@ func (this ActivityStreamsArticle) GetGoToSocialInteractionPolicy() vocab.GoToSo
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsArticle) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsArticle) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -686,6 +700,7 @@ func (this ActivityStreamsArticle) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1068,6 +1083,20 @@ func (this ActivityStreamsArticle) LessThan(o vocab.ActivityStreamsArticle) bool
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1439,6 +1468,14 @@ func (this ActivityStreamsArticle) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1703,6 +1740,11 @@ func (this *ActivityStreamsArticle) SetGoToSocialInteractionPolicy(i vocab.GoToS
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsArticle) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsArticle) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -22,46 +22,47 @@ import (
|
|||
// }
|
||||
// }
|
||||
type ActivityStreamsAudio struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsAudioExtends returns true if the Audio type extends from the
|
||||
|
|
@ -273,6 +274,11 @@ func DeserializeAudio(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -388,6 +394,8 @@ func DeserializeAudio(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -641,6 +649,12 @@ func (this ActivityStreamsAudio) GetGoToSocialInteractionPolicy() vocab.GoToSoci
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsAudio) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsAudio) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -715,6 +729,7 @@ func (this ActivityStreamsAudio) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1125,6 +1140,20 @@ func (this ActivityStreamsAudio) LessThan(o vocab.ActivityStreamsAudio) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1512,6 +1541,14 @@ func (this ActivityStreamsAudio) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1776,6 +1813,11 @@ func (this *ActivityStreamsAudio) SetGoToSocialInteractionPolicy(i vocab.GoToSoc
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsAudio) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsAudio) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -18,46 +18,47 @@ import (
|
|||
// "url": "http://example.org/4q-sales-forecast.pdf"
|
||||
// }
|
||||
type ActivityStreamsDocument struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsDocumentExtends returns true if the Document type extends from
|
||||
|
|
@ -249,6 +250,11 @@ func DeserializeDocument(m map[string]interface{}, aliasMap map[string]string) (
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -364,6 +370,8 @@ func DeserializeDocument(m map[string]interface{}, aliasMap map[string]string) (
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -642,6 +650,12 @@ func (this ActivityStreamsDocument) GetGoToSocialInteractionPolicy() vocab.GoToS
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsDocument) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsDocument) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -716,6 +730,7 @@ func (this ActivityStreamsDocument) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1126,6 +1141,20 @@ func (this ActivityStreamsDocument) LessThan(o vocab.ActivityStreamsDocument) bo
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1513,6 +1542,14 @@ func (this ActivityStreamsDocument) Serialize() (map[string]interface{}, error)
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1777,6 +1814,11 @@ func (this *ActivityStreamsDocument) SetGoToSocialInteractionPolicy(i vocab.GoTo
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsDocument) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsDocument) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -19,44 +19,45 @@ import (
|
|||
// "type": "Event"
|
||||
// }
|
||||
type ActivityStreamsEvent struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsEventExtends returns true if the Event type extends from the
|
||||
|
|
@ -238,6 +239,11 @@ func DeserializeEvent(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -349,6 +355,8 @@ func DeserializeEvent(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -622,6 +630,12 @@ func (this ActivityStreamsEvent) GetGoToSocialInteractionPolicy() vocab.GoToSoci
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsEvent) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsEvent) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -683,6 +697,7 @@ func (this ActivityStreamsEvent) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1065,6 +1080,20 @@ func (this ActivityStreamsEvent) LessThan(o vocab.ActivityStreamsEvent) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1436,6 +1465,14 @@ func (this ActivityStreamsEvent) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1700,6 +1737,11 @@ func (this *ActivityStreamsEvent) SetGoToSocialInteractionPolicy(i vocab.GoToSoc
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsEvent) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsEvent) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -129,6 +129,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -29,48 +29,49 @@ import (
|
|||
// ]
|
||||
// }
|
||||
type ActivityStreamsImage struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsHeight vocab.ActivityStreamsHeightProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
ActivityStreamsWidth vocab.ActivityStreamsWidthProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsHeight vocab.ActivityStreamsHeightProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
ActivityStreamsWidth vocab.ActivityStreamsWidthProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsImageExtends returns true if the Image type extends from the
|
||||
|
|
@ -267,6 +268,11 @@ func DeserializeImage(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -389,6 +395,8 @@ func DeserializeImage(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -676,6 +684,12 @@ func (this ActivityStreamsImage) GetGoToSocialInteractionPolicy() vocab.GoToSoci
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsImage) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsImage) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -751,6 +765,7 @@ func (this ActivityStreamsImage) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1176,6 +1191,20 @@ func (this ActivityStreamsImage) LessThan(o vocab.ActivityStreamsImage) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1585,6 +1614,14 @@ func (this ActivityStreamsImage) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1867,6 +1904,11 @@ func (this *ActivityStreamsImage) SetGoToSocialInteractionPolicy(i vocab.GoToSoc
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsImage) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsImage) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ type privateManager interface {
|
|||
// deserialization method for the "ActivityStreamsInstrumentProperty"
|
||||
// non-functional property in the vocabulary "ActivityStreams"
|
||||
DeserializeInstrumentPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsInstrumentProperty, error)
|
||||
// DeserializeLikeAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialLikeAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeLikeAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialLikeAuthorizationProperty, error)
|
||||
// DeserializeLikesPropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsLikesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type ActivityStreamsLike struct {
|
|||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
ActivityStreamsInstrument vocab.ActivityStreamsInstrumentProperty
|
||||
GoToSocialLikeAuthorization vocab.GoToSocialLikeAuthorizationProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
|
|
@ -211,6 +212,11 @@ func DeserializeLike(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsInstrument = p
|
||||
}
|
||||
if p, err := mgr.DeserializeLikeAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialLikeAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeLikesPropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -361,6 +367,8 @@ func DeserializeLike(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
continue
|
||||
} else if k == "instrument" {
|
||||
continue
|
||||
} else if k == "likeAuthorization" {
|
||||
continue
|
||||
} else if k == "likes" {
|
||||
continue
|
||||
} else if k == "location" {
|
||||
|
|
@ -682,6 +690,12 @@ func (this ActivityStreamsLike) GetGoToSocialApprovedBy() vocab.GoToSocialApprov
|
|||
return this.GoToSocialApprovedBy
|
||||
}
|
||||
|
||||
// GetGoToSocialLikeAuthorization returns the "likeAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsLike) GetGoToSocialLikeAuthorization() vocab.GoToSocialLikeAuthorizationProperty {
|
||||
return this.GoToSocialLikeAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsLike) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -736,6 +750,7 @@ func (this ActivityStreamsLike) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsImage, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsInReplyTo, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsInstrument, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialLikeAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsLikes, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsLocation, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsMediaType, m)
|
||||
|
|
@ -1031,6 +1046,20 @@ func (this ActivityStreamsLike) LessThan(o vocab.ActivityStreamsLike) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "likeAuthorization"
|
||||
if lhs, rhs := this.GoToSocialLikeAuthorization, o.GetGoToSocialLikeAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "likes"
|
||||
if lhs, rhs := this.ActivityStreamsLikes, o.GetActivityStreamsLikes(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1500,6 +1529,14 @@ func (this ActivityStreamsLike) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsInstrument.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "likeAuthorization"
|
||||
if this.GoToSocialLikeAuthorization != nil {
|
||||
if i, err := this.GoToSocialLikeAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialLikeAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "likes"
|
||||
if this.ActivityStreamsLikes != nil {
|
||||
if i, err := this.ActivityStreamsLikes.Serialize(); err != nil {
|
||||
|
|
@ -1872,6 +1909,11 @@ func (this *ActivityStreamsLike) SetGoToSocialApprovedBy(i vocab.GoToSocialAppro
|
|||
this.GoToSocialApprovedBy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialLikeAuthorization sets the "likeAuthorization" property.
|
||||
func (this *ActivityStreamsLike) SetGoToSocialLikeAuthorization(i vocab.GoToSocialLikeAuthorizationProperty) {
|
||||
this.GoToSocialLikeAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsLike) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -19,44 +19,45 @@ import (
|
|||
// "type": "Note"
|
||||
// }
|
||||
type ActivityStreamsNote struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsNoteExtends returns true if the Note type extends from the other
|
||||
|
|
@ -238,6 +239,11 @@ func DeserializeNote(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -349,6 +355,8 @@ func DeserializeNote(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -622,6 +630,12 @@ func (this ActivityStreamsNote) GetGoToSocialInteractionPolicy() vocab.GoToSocia
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsNote) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsNote) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -683,6 +697,7 @@ func (this ActivityStreamsNote) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1065,6 +1080,20 @@ func (this ActivityStreamsNote) LessThan(o vocab.ActivityStreamsNote) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1436,6 +1465,14 @@ func (this ActivityStreamsNote) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1700,6 +1737,11 @@ func (this *ActivityStreamsNote) SetGoToSocialInteractionPolicy(i vocab.GoToSoci
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsNote) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsNote) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -18,46 +18,47 @@ import (
|
|||
// "url": "http://example.org/weather-in-omaha.html"
|
||||
// }
|
||||
type ActivityStreamsPage struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsPageExtends returns true if the Page type extends from the other
|
||||
|
|
@ -249,6 +250,11 @@ func DeserializePage(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -364,6 +370,8 @@ func DeserializePage(m map[string]interface{}, aliasMap map[string]string) (*Act
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -637,6 +645,12 @@ func (this ActivityStreamsPage) GetGoToSocialInteractionPolicy() vocab.GoToSocia
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsPage) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsPage) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -711,6 +725,7 @@ func (this ActivityStreamsPage) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1121,6 +1136,20 @@ func (this ActivityStreamsPage) LessThan(o vocab.ActivityStreamsPage) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1508,6 +1537,14 @@ func (this ActivityStreamsPage) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1772,6 +1809,11 @@ func (this *ActivityStreamsPage) SetGoToSocialInteractionPolicy(i vocab.GoToSoci
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsPage) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsPage) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -29,49 +29,50 @@ import (
|
|||
// "units": "miles"
|
||||
// }
|
||||
type ActivityStreamsPlace struct {
|
||||
ActivityStreamsAccuracy vocab.ActivityStreamsAccuracyProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLatitude vocab.ActivityStreamsLatitudeProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsLongitude vocab.ActivityStreamsLongitudeProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsRadius vocab.ActivityStreamsRadiusProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUnits vocab.ActivityStreamsUnitsProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAccuracy vocab.ActivityStreamsAccuracyProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLatitude vocab.ActivityStreamsLatitudeProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsLongitude vocab.ActivityStreamsLongitudeProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsRadius vocab.ActivityStreamsRadiusProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUnits vocab.ActivityStreamsUnitsProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsPlaceExtends returns true if the Place type extends from the
|
||||
|
|
@ -273,6 +274,11 @@ func DeserializePlace(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -397,6 +403,8 @@ func DeserializePlace(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -702,6 +710,12 @@ func (this ActivityStreamsPlace) GetGoToSocialInteractionPolicy() vocab.GoToSoci
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsPlace) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsPlace) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -767,6 +781,7 @@ func (this ActivityStreamsPlace) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsRadius, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1206,6 +1221,20 @@ func (this ActivityStreamsPlace) LessThan(o vocab.ActivityStreamsPlace) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1623,6 +1652,14 @@ func (this ActivityStreamsPlace) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1920,6 +1957,11 @@ func (this *ActivityStreamsPlace) SetGoToSocialInteractionPolicy(i vocab.GoToSoc
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsPlace) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsPlace) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -121,6 +121,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -23,45 +23,46 @@ import (
|
|||
// "type": "Profile"
|
||||
// }
|
||||
type ActivityStreamsProfile struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDescribes vocab.ActivityStreamsDescribesProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDescribes vocab.ActivityStreamsDescribesProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsProfileExtends returns true if the Profile type extends from the
|
||||
|
|
@ -248,6 +249,11 @@ func DeserializeProfile(m map[string]interface{}, aliasMap map[string]string) (*
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -361,6 +367,8 @@ func DeserializeProfile(m map[string]interface{}, aliasMap map[string]string) (*
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -640,6 +648,12 @@ func (this ActivityStreamsProfile) GetGoToSocialInteractionPolicy() vocab.GoToSo
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsProfile) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsProfile) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -702,6 +716,7 @@ func (this ActivityStreamsProfile) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1098,6 +1113,20 @@ func (this ActivityStreamsProfile) LessThan(o vocab.ActivityStreamsProfile) bool
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1477,6 +1506,14 @@ func (this ActivityStreamsProfile) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1746,6 +1783,11 @@ func (this *ActivityStreamsProfile) SetGoToSocialInteractionPolicy(i vocab.GoToS
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsProfile) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsProfile) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -137,6 +137,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeResultPropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsResultProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -40,52 +40,53 @@ import (
|
|||
// "type": "Question"
|
||||
// }
|
||||
type ActivityStreamsQuestion struct {
|
||||
ActivityStreamsActor vocab.ActivityStreamsActorProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
ActivityStreamsAnyOf vocab.ActivityStreamsAnyOfProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsClosed vocab.ActivityStreamsClosedProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
ActivityStreamsInstrument vocab.ActivityStreamsInstrumentProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsOneOf vocab.ActivityStreamsOneOfProperty
|
||||
ActivityStreamsOrigin vocab.ActivityStreamsOriginProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsResult vocab.ActivityStreamsResultProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTarget vocab.ActivityStreamsTargetProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
TootVotersCount vocab.TootVotersCountProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsActor vocab.ActivityStreamsActorProperty
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
ActivityStreamsAnyOf vocab.ActivityStreamsAnyOfProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsClosed vocab.ActivityStreamsClosedProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
ActivityStreamsInstrument vocab.ActivityStreamsInstrumentProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsOneOf vocab.ActivityStreamsOneOfProperty
|
||||
ActivityStreamsOrigin vocab.ActivityStreamsOriginProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsResult vocab.ActivityStreamsResultProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTarget vocab.ActivityStreamsTargetProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
TootVotersCount vocab.TootVotersCountProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsQuestionExtends returns true if the Question type extends from
|
||||
|
|
@ -292,6 +293,11 @@ func DeserializeQuestion(m map[string]interface{}, aliasMap map[string]string) (
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeResultPropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -428,6 +434,8 @@ func DeserializeQuestion(m map[string]interface{}, aliasMap map[string]string) (
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "result" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
|
|
@ -749,6 +757,12 @@ func (this ActivityStreamsQuestion) GetGoToSocialInteractionPolicy() vocab.GoToS
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsQuestion) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsQuestion) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -821,6 +835,7 @@ func (this ActivityStreamsQuestion) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsResult, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
|
|
@ -1276,6 +1291,20 @@ func (this ActivityStreamsQuestion) LessThan(o vocab.ActivityStreamsQuestion) bo
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "result"
|
||||
if lhs, rhs := this.ActivityStreamsResult, o.GetActivityStreamsResult(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1729,6 +1758,14 @@ func (this ActivityStreamsQuestion) Serialize() (map[string]interface{}, error)
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "result"
|
||||
if this.ActivityStreamsResult != nil {
|
||||
if i, err := this.ActivityStreamsResult.Serialize(); err != nil {
|
||||
|
|
@ -2052,6 +2089,11 @@ func (this *ActivityStreamsQuestion) SetGoToSocialInteractionPolicy(i vocab.GoTo
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsQuestion) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsQuestion) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ type privateManager interface {
|
|||
// method for the "ActivityStreamsRepliesProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
DeserializeRepliesPropertyActivityStreams() func(map[string]interface{}, map[string]string) (vocab.ActivityStreamsRepliesProperty, error)
|
||||
// DeserializeReplyAuthorizationPropertyGoToSocial returns the
|
||||
// deserialization method for the
|
||||
// "GoToSocialReplyAuthorizationProperty" non-functional property in
|
||||
// the vocabulary "GoToSocial"
|
||||
DeserializeReplyAuthorizationPropertyGoToSocial() func(map[string]interface{}, map[string]string) (vocab.GoToSocialReplyAuthorizationProperty, error)
|
||||
// DeserializeSensitivePropertyActivityStreams returns the deserialization
|
||||
// method for the "ActivityStreamsSensitiveProperty" non-functional
|
||||
// property in the vocabulary "ActivityStreams"
|
||||
|
|
|
|||
|
|
@ -19,46 +19,47 @@ import (
|
|||
// "url": "http://example.org/video.mkv"
|
||||
// }
|
||||
type ActivityStreamsVideo struct {
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
ActivityStreamsAltitude vocab.ActivityStreamsAltitudeProperty
|
||||
GoToSocialApprovedBy vocab.GoToSocialApprovedByProperty
|
||||
ActivityStreamsAttachment vocab.ActivityStreamsAttachmentProperty
|
||||
ActivityStreamsAttributedTo vocab.ActivityStreamsAttributedToProperty
|
||||
ActivityStreamsAudience vocab.ActivityStreamsAudienceProperty
|
||||
ActivityStreamsBcc vocab.ActivityStreamsBccProperty
|
||||
TootBlurhash vocab.TootBlurhashProperty
|
||||
ActivityStreamsBto vocab.ActivityStreamsBtoProperty
|
||||
ActivityStreamsCc vocab.ActivityStreamsCcProperty
|
||||
ActivityStreamsContent vocab.ActivityStreamsContentProperty
|
||||
ActivityStreamsContext vocab.ActivityStreamsContextProperty
|
||||
ActivityStreamsDuration vocab.ActivityStreamsDurationProperty
|
||||
ActivityStreamsEndTime vocab.ActivityStreamsEndTimeProperty
|
||||
TootFocalPoint vocab.TootFocalPointProperty
|
||||
ActivityStreamsGenerator vocab.ActivityStreamsGeneratorProperty
|
||||
ActivityStreamsIcon vocab.ActivityStreamsIconProperty
|
||||
JSONLDId vocab.JSONLDIdProperty
|
||||
ActivityStreamsImage vocab.ActivityStreamsImageProperty
|
||||
ActivityStreamsInReplyTo vocab.ActivityStreamsInReplyToProperty
|
||||
GoToSocialInteractionPolicy vocab.GoToSocialInteractionPolicyProperty
|
||||
ActivityStreamsLikes vocab.ActivityStreamsLikesProperty
|
||||
ActivityStreamsLocation vocab.ActivityStreamsLocationProperty
|
||||
ActivityStreamsMediaType vocab.ActivityStreamsMediaTypeProperty
|
||||
ActivityStreamsName vocab.ActivityStreamsNameProperty
|
||||
ActivityStreamsObject vocab.ActivityStreamsObjectProperty
|
||||
ActivityStreamsPreview vocab.ActivityStreamsPreviewProperty
|
||||
ActivityStreamsPublished vocab.ActivityStreamsPublishedProperty
|
||||
ActivityStreamsReplies vocab.ActivityStreamsRepliesProperty
|
||||
GoToSocialReplyAuthorization vocab.GoToSocialReplyAuthorizationProperty
|
||||
ActivityStreamsSensitive vocab.ActivityStreamsSensitiveProperty
|
||||
ActivityStreamsShares vocab.ActivityStreamsSharesProperty
|
||||
ActivityStreamsSource vocab.ActivityStreamsSourceProperty
|
||||
ActivityStreamsStartTime vocab.ActivityStreamsStartTimeProperty
|
||||
ActivityStreamsSummary vocab.ActivityStreamsSummaryProperty
|
||||
ActivityStreamsTag vocab.ActivityStreamsTagProperty
|
||||
ActivityStreamsTo vocab.ActivityStreamsToProperty
|
||||
JSONLDType vocab.JSONLDTypeProperty
|
||||
ActivityStreamsUpdated vocab.ActivityStreamsUpdatedProperty
|
||||
ActivityStreamsUrl vocab.ActivityStreamsUrlProperty
|
||||
alias string
|
||||
unknown map[string]interface{}
|
||||
}
|
||||
|
||||
// ActivityStreamsVideoExtends returns true if the Video type extends from the
|
||||
|
|
@ -250,6 +251,11 @@ func DeserializeVideo(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
} else if p != nil {
|
||||
this.ActivityStreamsReplies = p
|
||||
}
|
||||
if p, err := mgr.DeserializeReplyAuthorizationPropertyGoToSocial()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
this.GoToSocialReplyAuthorization = p
|
||||
}
|
||||
if p, err := mgr.DeserializeSensitivePropertyActivityStreams()(m, aliasMap); err != nil {
|
||||
return nil, err
|
||||
} else if p != nil {
|
||||
|
|
@ -365,6 +371,8 @@ func DeserializeVideo(m map[string]interface{}, aliasMap map[string]string) (*Ac
|
|||
continue
|
||||
} else if k == "replies" {
|
||||
continue
|
||||
} else if k == "replyAuthorization" {
|
||||
continue
|
||||
} else if k == "sensitive" {
|
||||
continue
|
||||
} else if k == "shares" {
|
||||
|
|
@ -638,6 +646,12 @@ func (this ActivityStreamsVideo) GetGoToSocialInteractionPolicy() vocab.GoToSoci
|
|||
return this.GoToSocialInteractionPolicy
|
||||
}
|
||||
|
||||
// GetGoToSocialReplyAuthorization returns the "replyAuthorization" property if it
|
||||
// exists, and nil otherwise.
|
||||
func (this ActivityStreamsVideo) GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty {
|
||||
return this.GoToSocialReplyAuthorization
|
||||
}
|
||||
|
||||
// GetJSONLDId returns the "id" property if it exists, and nil otherwise.
|
||||
func (this ActivityStreamsVideo) GetJSONLDId() vocab.JSONLDIdProperty {
|
||||
return this.JSONLDId
|
||||
|
|
@ -712,6 +726,7 @@ func (this ActivityStreamsVideo) JSONLDContext() map[string]string {
|
|||
m = this.helperJSONLDContext(this.ActivityStreamsPreview, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsPublished, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsReplies, m)
|
||||
m = this.helperJSONLDContext(this.GoToSocialReplyAuthorization, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSensitive, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsShares, m)
|
||||
m = this.helperJSONLDContext(this.ActivityStreamsSource, m)
|
||||
|
|
@ -1122,6 +1137,20 @@ func (this ActivityStreamsVideo) LessThan(o vocab.ActivityStreamsVideo) bool {
|
|||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "replyAuthorization"
|
||||
if lhs, rhs := this.GoToSocialReplyAuthorization, o.GetGoToSocialReplyAuthorization(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
return true
|
||||
} else if rhs.LessThan(lhs) {
|
||||
return false
|
||||
}
|
||||
} else if lhs == nil && rhs != nil {
|
||||
// Nil is less than anything else
|
||||
return true
|
||||
} else if rhs != nil && rhs == nil {
|
||||
// Anything else is greater than nil
|
||||
return false
|
||||
} // Else: Both are nil
|
||||
// Compare property "sensitive"
|
||||
if lhs, rhs := this.ActivityStreamsSensitive, o.GetActivityStreamsSensitive(); lhs != nil && rhs != nil {
|
||||
if lhs.LessThan(rhs) {
|
||||
|
|
@ -1509,6 +1538,14 @@ func (this ActivityStreamsVideo) Serialize() (map[string]interface{}, error) {
|
|||
m[this.ActivityStreamsReplies.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "replyAuthorization"
|
||||
if this.GoToSocialReplyAuthorization != nil {
|
||||
if i, err := this.GoToSocialReplyAuthorization.Serialize(); err != nil {
|
||||
return nil, err
|
||||
} else if i != nil {
|
||||
m[this.GoToSocialReplyAuthorization.Name()] = i
|
||||
}
|
||||
}
|
||||
// Maybe serialize property "sensitive"
|
||||
if this.ActivityStreamsSensitive != nil {
|
||||
if i, err := this.ActivityStreamsSensitive.Serialize(); err != nil {
|
||||
|
|
@ -1773,6 +1810,11 @@ func (this *ActivityStreamsVideo) SetGoToSocialInteractionPolicy(i vocab.GoToSoc
|
|||
this.GoToSocialInteractionPolicy = i
|
||||
}
|
||||
|
||||
// SetGoToSocialReplyAuthorization sets the "replyAuthorization" property.
|
||||
func (this *ActivityStreamsVideo) SetGoToSocialReplyAuthorization(i vocab.GoToSocialReplyAuthorizationProperty) {
|
||||
this.GoToSocialReplyAuthorization = i
|
||||
}
|
||||
|
||||
// SetJSONLDId sets the "id" property.
|
||||
func (this *ActivityStreamsVideo) SetJSONLDId(i vocab.JSONLDIdProperty) {
|
||||
this.JSONLDId = i
|
||||
|
|
|
|||
17
vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_doc.go
generated
vendored
Normal file
17
vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Code generated by astool. DO NOT EDIT.
|
||||
|
||||
// Package propertyannounceauthorization contains the implementation for the
|
||||
// announceAuthorization property. All applications are strongly encouraged to
|
||||
// use the interface instead of this concrete definition. The interfaces allow
|
||||
// applications to consume only the types and properties needed and be
|
||||
// independent of the go-fed implementation if another alternative
|
||||
// implementation is created. This package is code-generated and subject to
|
||||
// the same license as the go-fed tool used to generate it.
|
||||
//
|
||||
// This package is independent of other types' and properties' implementations
|
||||
// by having a Manager injected into it to act as a factory for the concrete
|
||||
// implementations. The implementations have been generated into their own
|
||||
// separate subpackages for each vocabulary.
|
||||
//
|
||||
// Strongly consider using the interfaces instead of this package.
|
||||
package propertyannounceauthorization
|
||||
15
vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_pkg.go
generated
vendored
Normal file
15
vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_pkg.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Code generated by astool. DO NOT EDIT.
|
||||
|
||||
package propertyannounceauthorization
|
||||
|
||||
var mgr privateManager
|
||||
|
||||
// privateManager abstracts the code-generated manager that provides access to
|
||||
// concrete implementations.
|
||||
type privateManager interface{}
|
||||
|
||||
// SetManager sets the manager package-global variable. For internal use only, do
|
||||
// not use as part of Application behavior. Must be called at golang init time.
|
||||
func SetManager(m privateManager) {
|
||||
mgr = m
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
// Code generated by astool. DO NOT EDIT.
|
||||
|
||||
package propertyannounceauthorization
|
||||
|
||||
import (
|
||||
anyuri "code.superseriousbusiness.org/activity/streams/values/anyURI"
|
||||
vocab "code.superseriousbusiness.org/activity/streams/vocab"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// GoToSocialAnnounceAuthorizationProperty is the functional property
|
||||
// "announceAuthorization". It is permitted to be a single nilable value type.
|
||||
type GoToSocialAnnounceAuthorizationProperty struct {
|
||||
xmlschemaAnyURIMember *url.URL
|
||||
unknown interface{}
|
||||
alias string
|
||||
}
|
||||
|
||||
// DeserializeAnnounceAuthorizationProperty creates a "announceAuthorization"
|
||||
// property from an interface representation that has been unmarshalled from a
|
||||
// text or binary format.
|
||||
func DeserializeAnnounceAuthorizationProperty(m map[string]interface{}, aliasMap map[string]string) (*GoToSocialAnnounceAuthorizationProperty, error) {
|
||||
alias := ""
|
||||
if a, ok := aliasMap["https://gotosocial.org/ns"]; ok {
|
||||
alias = a
|
||||
}
|
||||
propName := "announceAuthorization"
|
||||
if len(alias) > 0 {
|
||||
// Use alias both to find the property, and set within the property.
|
||||
propName = fmt.Sprintf("%s:%s", alias, "announceAuthorization")
|
||||
}
|
||||
i, ok := m[propName]
|
||||
|
||||
if ok {
|
||||
if v, err := anyuri.DeserializeAnyURI(i); err == nil {
|
||||
this := &GoToSocialAnnounceAuthorizationProperty{
|
||||
alias: alias,
|
||||
xmlschemaAnyURIMember: v,
|
||||
}
|
||||
return this, nil
|
||||
}
|
||||
this := &GoToSocialAnnounceAuthorizationProperty{
|
||||
alias: alias,
|
||||
unknown: i,
|
||||
}
|
||||
return this, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewGoToSocialAnnounceAuthorizationProperty creates a new announceAuthorization
|
||||
// property.
|
||||
func NewGoToSocialAnnounceAuthorizationProperty() *GoToSocialAnnounceAuthorizationProperty {
|
||||
return &GoToSocialAnnounceAuthorizationProperty{alias: ""}
|
||||
}
|
||||
|
||||
// Clear ensures no value of this property is set. Calling IsXMLSchemaAnyURI
|
||||
// afterwards will return false.
|
||||
func (this *GoToSocialAnnounceAuthorizationProperty) Clear() {
|
||||
this.unknown = nil
|
||||
this.xmlschemaAnyURIMember = nil
|
||||
}
|
||||
|
||||
// Get returns the value of this property. When IsXMLSchemaAnyURI returns false,
|
||||
// Get will return any arbitrary value.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) Get() *url.URL {
|
||||
return this.xmlschemaAnyURIMember
|
||||
}
|
||||
|
||||
// GetIRI returns the IRI of this property. When IsIRI returns false, GetIRI will
|
||||
// return any arbitrary value.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) GetIRI() *url.URL {
|
||||
return this.xmlschemaAnyURIMember
|
||||
}
|
||||
|
||||
// HasAny returns true if the value or IRI is set.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) HasAny() bool {
|
||||
return this.IsXMLSchemaAnyURI()
|
||||
}
|
||||
|
||||
// IsIRI returns true if this property is an IRI.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) IsIRI() bool {
|
||||
return this.xmlschemaAnyURIMember != nil
|
||||
}
|
||||
|
||||
// IsXMLSchemaAnyURI returns true if this property is set and not an IRI.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) IsXMLSchemaAnyURI() bool {
|
||||
return this.xmlschemaAnyURIMember != nil
|
||||
}
|
||||
|
||||
// JSONLDContext returns the JSONLD URIs required in the context string for this
|
||||
// property and the specific values that are set. The value in the map is the
|
||||
// alias used to import the property's value or values.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) JSONLDContext() map[string]string {
|
||||
m := map[string]string{"https://gotosocial.org/ns": this.alias}
|
||||
var child map[string]string
|
||||
|
||||
/*
|
||||
Since the literal maps in this function are determined at
|
||||
code-generation time, this loop should not overwrite an existing key with a
|
||||
new value.
|
||||
*/
|
||||
for k, v := range child {
|
||||
m[k] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// KindIndex computes an arbitrary value for indexing this kind of value. This is
|
||||
// a leaky API detail only for folks looking to replace the go-fed
|
||||
// implementation. Applications should not use this method.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) KindIndex() int {
|
||||
if this.IsXMLSchemaAnyURI() {
|
||||
return 0
|
||||
}
|
||||
if this.IsIRI() {
|
||||
return -2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LessThan compares two instances of this property with an arbitrary but stable
|
||||
// comparison. Applications should not use this because it is only meant to
|
||||
// help alternative implementations to go-fed to be able to normalize
|
||||
// nonfunctional properties.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) LessThan(o vocab.GoToSocialAnnounceAuthorizationProperty) bool {
|
||||
if this.IsIRI() {
|
||||
// IRIs are always less than other values, none, or unknowns
|
||||
return true
|
||||
} else if o.IsIRI() {
|
||||
// This other, none, or unknown value is always greater than IRIs
|
||||
return false
|
||||
}
|
||||
// LessThan comparison for the single value or unknown value.
|
||||
if !this.IsXMLSchemaAnyURI() && !o.IsXMLSchemaAnyURI() {
|
||||
// Both are unknowns.
|
||||
return false
|
||||
} else if this.IsXMLSchemaAnyURI() && !o.IsXMLSchemaAnyURI() {
|
||||
// Values are always greater than unknown values.
|
||||
return false
|
||||
} else if !this.IsXMLSchemaAnyURI() && o.IsXMLSchemaAnyURI() {
|
||||
// Unknowns are always less than known values.
|
||||
return true
|
||||
} else {
|
||||
// Actual comparison.
|
||||
return anyuri.LessAnyURI(this.Get(), o.Get())
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the name of this property: "announceAuthorization".
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) Name() string {
|
||||
if len(this.alias) > 0 {
|
||||
return this.alias + ":" + "announceAuthorization"
|
||||
} else {
|
||||
return "announceAuthorization"
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize converts this into an interface representation suitable for
|
||||
// marshalling into a text or binary format. Applications should not need this
|
||||
// function as most typical use cases serialize types instead of individual
|
||||
// properties. It is exposed for alternatives to go-fed implementations to use.
|
||||
func (this GoToSocialAnnounceAuthorizationProperty) Serialize() (interface{}, error) {
|
||||
if this.IsXMLSchemaAnyURI() {
|
||||
return anyuri.SerializeAnyURI(this.Get())
|
||||
}
|
||||
return this.unknown, nil
|
||||
}
|
||||
|
||||
// Set sets the value of this property. Calling IsXMLSchemaAnyURI afterwards will
|
||||
// return true.
|
||||
func (this *GoToSocialAnnounceAuthorizationProperty) Set(v *url.URL) {
|
||||
this.Clear()
|
||||
this.xmlschemaAnyURIMember = v
|
||||
}
|
||||
|
||||
// SetIRI sets the value of this property. Calling IsIRI afterwards will return
|
||||
// true.
|
||||
func (this *GoToSocialAnnounceAuthorizationProperty) SetIRI(v *url.URL) {
|
||||
this.Clear()
|
||||
this.Set(v)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue