diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index 6ee4db4ab..b84a3e21b 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -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 diff --git a/go.mod b/go.mod index 6b64ae9b8..2915d9847 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 727cc45fc..de3bbb155 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/internal/ap/activitystreams.go b/internal/ap/activitystreams.go index 56ebc4909..9c2464410 100644 --- a/internal/ap/activitystreams.go +++ b/internal/ap/activitystreams.go @@ -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 diff --git a/internal/ap/ap_test.go b/internal/ap/ap_test.go index 0956fee66..9f275434d 100644 --- a/internal/ap/ap_test.go +++ b/internal/ap/ap_test.go @@ -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) diff --git a/internal/ap/extract.go b/internal/ap/extract.go index 7a727b005..f26b02a82 100644 --- a/internal/ap/extract.go +++ b/internal/ap/extract.go @@ -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 } diff --git a/internal/ap/interfaces.go b/internal/ap/interfaces.go index ec961f80b..3224cecc0 100644 --- a/internal/ap/interfaces.go +++ b/internal/ap/interfaces.go @@ -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) +} diff --git a/internal/ap/properties.go b/internal/ap/properties.go index 3e064bae0..51e4ab1c0 100644 --- a/internal/ap/properties.go +++ b/internal/ap/properties.go @@ -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. // diff --git a/internal/ap/serialize.go b/internal/ap/serialize.go index c64c14d75..10af16ea4 100644 --- a/internal/ap/serialize.go +++ b/internal/ap/serialize.go @@ -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 diff --git a/internal/api/activitypub/users/authorizationget.go b/internal/api/activitypub/users/authorizationget.go new file mode 100644 index 000000000..a7f234854 --- /dev/null +++ b/internal/api/activitypub/users/authorizationget.go @@ -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 . + +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) +} diff --git a/internal/api/activitypub/users/inboxpost_test.go b/internal/api/activitypub/users/inboxpost_test.go index 81b21eafc..51df35672 100644 --- a/internal/api/activitypub/users/inboxpost_test.go +++ b/internal/api/activitypub/users/inboxpost_test.go @@ -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 diff --git a/internal/api/activitypub/users/user.go b/internal/api/activitypub/users/user.go index 7a06e6f03..7fb5f6aa5 100644 --- a/internal/api/activitypub/users/user.go +++ b/internal/api/activitypub/users/user.go @@ -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) } diff --git a/internal/api/client/statuses/statusboost_test.go b/internal/api/client/statuses/statusboost_test.go index a108c436c..2b6925f3b 100644 --- a/internal/api/client/statuses/statusboost_test.go +++ b/internal/api/client/statuses/statusboost_test.go @@ -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) { diff --git a/internal/api/client/statuses/statusfave_test.go b/internal/api/client/statuses/statusfave_test.go index 515b66a3c..f1c6f8eae 100644 --- a/internal/api/client/statuses/statusfave_test.go +++ b/internal/api/client/statuses/statusfave_test.go @@ -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) diff --git a/internal/api/model/interaction.go b/internal/api/model/interaction.go index b0543ce6b..0dea6cae9 100644 --- a/internal/api/model/interaction.go +++ b/internal/api/model/interaction.go @@ -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"` } diff --git a/internal/cache/db.go b/internal/cache/db.go index 385c5bcbb..8a8f59539 100644 --- a/internal/cache/db.go +++ b/internal/cache/db.go @@ -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, diff --git a/internal/cache/size.go b/internal/cache/size.go index aa22b03d7..cf58cf075 100644 --- a/internal/cache/size.go +++ b/internal/cache/size.go @@ -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, })) } diff --git a/internal/db/bundb/admin.go b/internal/db/bundb/admin.go index dcf51c6a5..39b2c848f 100644 --- a/internal/db/bundb/admin.go +++ b/internal/db/bundb/admin.go @@ -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), diff --git a/internal/db/bundb/interaction.go b/internal/db/bundb/interaction.go index b42eb46f6..2128a7aa6 100644 --- a/internal/db/bundb/interaction.go +++ b/internal/db/bundb/interaction.go @@ -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) diff --git a/internal/db/bundb/interaction_test.go b/internal/db/bundb/interaction_test.go index 564b3a3f2..6a753dca8 100644 --- a/internal/db/bundb/interaction_test.go +++ b/internal/db/bundb/interaction_test.go @@ -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()) } diff --git a/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat.go b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat.go new file mode 100644 index 000000000..0df515082 --- /dev/null +++ b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat.go @@ -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 . + +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) + } +} diff --git a/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/new/interactionrequest.go b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/new/interactionrequest.go new file mode 100644 index 000000000..bdd2d5811 --- /dev/null +++ b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/new/interactionrequest.go @@ -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 . + +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" +) diff --git a/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/old/interactionrequest.go b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/old/interactionrequest.go new file mode 100644 index 000000000..a341f4d5b --- /dev/null +++ b/internal/db/bundb/migrations/20250715095446_int_pols_forward_compat/old/interactionrequest.go @@ -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 . + +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 +) diff --git a/internal/db/bundb/notification_test.go b/internal/db/bundb/notification_test.go index 10b82b7ce..5b67d4f58 100644 --- a/internal/db/bundb/notification_test.go +++ b/internal/db/bundb/notification_test.go @@ -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), } diff --git a/internal/db/interaction.go b/internal/db/interaction.go index 4a6ec7e2e..9b45a6ab4 100644 --- a/internal/db/interaction.go +++ b/internal/db/interaction.go @@ -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 diff --git a/internal/federation/dereferencing/status_permitted.go b/internal/federation/dereferencing/status_permitted.go index 848a821d1..5e53d56bc 100644 --- a/internal/federation/dereferencing/status_permitted.go +++ b/internal/federation/dereferencing/status_permitted.go @@ -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 diff --git a/internal/federation/dereferencing/status_test.go b/internal/federation/dereferencing/status_test.go index e44babbfc..62b38f188 100644 --- a/internal/federation/dereferencing/status_test.go +++ b/internal/federation/dereferencing/status_test.go @@ -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("

Babe are you okay, you've hardly touched your #piss

", status.Content) + suite.Equal("

@foss_satanBabe are you okay, you've hardly touched your #piss

", status.Content) suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI) suite.False(*status.Local) suite.Empty(status.ContentWarning) diff --git a/internal/federation/federatingactor_test.go b/internal/federation/federatingactor_test.go index 51ead5f31..6de4aa203 100644 --- a/internal/federation/federatingactor_test.go +++ b/internal/federation/federatingactor_test.go @@ -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) diff --git a/internal/federation/federatingdb/accept.go b/internal/federation/federatingdb/accept.go index 2e4948a0e..d7606c4fa 100644 --- a/internal/federation/federatingdb/accept.go +++ b/internal/federation/federatingdb/accept.go @@ -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 diff --git a/internal/federation/federatingdb/accept_test.go b/internal/federation/federatingdb/accept_test.go new file mode 100644 index 000000000..2651c6a5f --- /dev/null +++ b/internal/federation/federatingdb/accept_test.go @@ -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 . + +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)) +} diff --git a/internal/federation/federatingdb/block.go b/internal/federation/federatingdb/block.go index 2950aef3b..e44081a56 100644 --- a/internal/federation/federatingdb/block.go +++ b/internal/federation/federatingdb/block.go @@ -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 diff --git a/internal/federation/federatingdb/create.go b/internal/federation/federatingdb/create.go index 8de137d6c..d3ce2bfa5 100644 --- a/internal/federation/federatingdb/create.go +++ b/internal/federation/federatingdb/create.go @@ -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 diff --git a/internal/federation/federatingdb/interactionrequest.go b/internal/federation/federatingdb/interactionrequest.go new file mode 100644 index 000000000..0026337d0 --- /dev/null +++ b/internal/federation/federatingdb/interactionrequest.go @@ -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 . + +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 +} diff --git a/internal/federation/federatingdb/interactionrequest_test.go b/internal/federation/federatingdb/interactionrequest_test.go new file mode 100644 index 000000000..81c0848ed --- /dev/null +++ b/internal/federation/federatingdb/interactionrequest_test.go @@ -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 . + +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{}) +} diff --git a/internal/federation/federatingdb/like.go b/internal/federation/federatingdb/like.go index debc343cf..ca26c0692 100644 --- a/internal/federation/federatingdb/like.go +++ b/internal/federation/federatingdb/like.go @@ -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 diff --git a/internal/federation/federatingdb/reject.go b/internal/federation/federatingdb/reject.go index 5ec3b1a27..88e5ca975 100644 --- a/internal/federation/federatingdb/reject.go +++ b/internal/federation/federatingdb/reject.go @@ -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) diff --git a/internal/federation/federatingdb/util.go b/internal/federation/federatingdb/util.go index 8124c8dc5..7e92707e7 100644 --- a/internal/federation/federatingdb/util.go +++ b/internal/federation/federatingdb/util.go @@ -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) + } +} diff --git a/internal/federation/federator.go b/internal/federation/federator.go index 5f8324da2..3f5c96002 100644 --- a/internal/federation/federator.go +++ b/internal/federation/federator.go @@ -99,6 +99,9 @@ func NewFederator( federatingDB.Announce, federatingDB.Move, federatingDB.Flag, + federatingDB.LikeRequest, + federatingDB.ReplyRequest, + federatingDB.AnnounceRequest, }, } actor := newFederatingActor(f, f, federatingDB, clock) diff --git a/internal/gtserror/error.go b/internal/gtserror/error.go index bd83a8dc8..8eb3f1d65 100644 --- a/internal/gtserror/error.go +++ b/internal/gtserror/error.go @@ -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 } diff --git a/internal/gtsmodel/interaction.go b/internal/gtsmodel/interaction.go index 0b9ee693e..a517236e2 100644 --- a/internal/gtsmodel/interaction.go +++ b/internal/gtsmodel/interaction.go @@ -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. diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index b6bc303cd..78aa09dd9 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -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{}. diff --git a/internal/id/ulid.go b/internal/id/ulid.go index 04afef8f0..f763a4772 100644 --- a/internal/id/ulid.go +++ b/internal/id/ulid.go @@ -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 } diff --git a/internal/processing/account/follow.go b/internal/processing/account/follow.go index 26d552bbb..91955eaa7 100644 --- a/internal/processing/account/follow.go +++ b/internal/processing/account/follow.go @@ -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{ diff --git a/internal/processing/admin/rule.go b/internal/processing/admin/rule.go index a665da9a1..de19cba0b 100644 --- a/internal/processing/admin/rule.go +++ b/internal/processing/admin/rule.go @@ -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) } diff --git a/internal/processing/application/create.go b/internal/processing/application/create.go index 7ee6fb6b9..d63b682d6 100644 --- a/internal/processing/application/create.go +++ b/internal/processing/application/create.go @@ -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. diff --git a/internal/processing/fedi/accept.go b/internal/processing/fedi/accept.go index e63b460db..97e36fbb3 100644 --- a/internal/processing/fedi/accept.go +++ b/internal/processing/fedi/accept.go @@ -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) } diff --git a/internal/processing/fedi/authorization.go b/internal/processing/fedi/authorization.go new file mode 100644 index 000000000..bbba6a2d8 --- /dev/null +++ b/internal/processing/fedi/authorization.go @@ -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 . + +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 +} diff --git a/internal/processing/fedi/common.go b/internal/processing/fedi/common.go index 9059aef39..fc783f93e 100644 --- a/internal/processing/fedi/common.go +++ b/internal/processing/fedi/common.go @@ -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 +} diff --git a/internal/processing/interactionrequests/accept.go b/internal/processing/interactionrequests/accept.go index ce682380b..7efd1f373 100644 --- a/internal/processing/interactionrequests/accept.go +++ b/internal/processing/interactionrequests/accept.go @@ -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, diff --git a/internal/processing/interactionrequests/accept_test.go b/internal/processing/interactionrequests/accept_test.go index b48978f2c..cb4212c24 100644 --- a/internal/processing/interactionrequests/accept_test.go +++ b/internal/processing/interactionrequests/accept_test.go @@ -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. diff --git a/internal/processing/interactionrequests/reject.go b/internal/processing/interactionrequests/reject.go index 3ceaa47d9..4db52e260 100644 --- a/internal/processing/interactionrequests/reject.go +++ b/internal/processing/interactionrequests/reject.go @@ -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) diff --git a/internal/processing/search/get.go b/internal/processing/search/get.go index 2e956b049..64aefd23c 100644 --- a/internal/processing/search/get.go +++ b/internal/processing/search/get.go @@ -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, diff --git a/internal/processing/workers/federate.go b/internal/processing/workers/federate.go index 3cc3d130c..7459f0114 100644 --- a/internal/processing/workers/federate.go +++ b/internal/processing/workers/federate.go @@ -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( diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go index 22e7780f6..9cdbcc548 100644 --- a/internal/processing/workers/fromclientapi.go +++ b/internal/processing/workers/fromclientapi.go @@ -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, diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go index 09c1df480..797a2d9c6 100644 --- a/internal/processing/workers/fromfediapi.go +++ b/internal/processing/workers/fromfediapi.go @@ -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 { diff --git a/internal/processing/workers/fromfediapi_test.go b/internal/processing/workers/fromfediapi_test.go index 7811e9f3d..790c78b70 100644 --- a/internal/processing/workers/fromfediapi_test.go +++ b/internal/processing/workers/fromfediapi_test.go @@ -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{}) } diff --git a/internal/processing/workers/util.go b/internal/processing/workers/util.go index 3c17eaaf5..6382887eb 100644 --- a/internal/processing/workers/util.go +++ b/internal/processing/workers/util.go @@ -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) } diff --git a/internal/transport/derefinstance.go b/internal/transport/derefinstance.go index 4c21355d6..4d15daf3d 100644 --- a/internal/transport/derefinstance.go +++ b/internal/transport/derefinstance.go @@ -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(), } diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go index ede2b3253..f352632b7 100644 --- a/internal/typeutils/astointernal.go +++ b/internal/typeutils/astointernal.go @@ -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() } diff --git a/internal/typeutils/internal.go b/internal/typeutils/internal.go index 4504168ef..a18b7a287 100644 --- a/internal/typeutils/internal.go +++ b/internal/typeutils/internal.go @@ -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, } } diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index 7cf736993..feb794e51 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -33,6 +33,7 @@ import ( "code.superseriousbusiness.org/gotosocial/internal/ap" "code.superseriousbusiness.org/gotosocial/internal/config" "code.superseriousbusiness.org/gotosocial/internal/db" + "code.superseriousbusiness.org/gotosocial/internal/gtscontext" "code.superseriousbusiness.org/gotosocial/internal/gtserror" "code.superseriousbusiness.org/gotosocial/internal/gtsmodel" "code.superseriousbusiness.org/gotosocial/internal/log" @@ -489,8 +490,9 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat return nil, gtserror.Newf("error populating status: %w", err) } - var status ap.Statusable - + // TODO: in future, allow longer + // posts to be federated as Articles. + var statusable ap.Statusable if s.Poll != nil { // If status has poll available, we convert // it as an AS Question (similar to a Note). @@ -502,80 +504,56 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat } // Set poll as status. - status = poll + statusable = poll } else { // Else we converter it as an AS Note. - status = streams.NewActivityStreamsNote() + statusable = streams.NewActivityStreamsNote() } - // id - statusURI, err := url.Parse(s.URI) - if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", s.URI, err) + // `id` property. + if err := ap.SetJSONLDIdStr(statusable, s.URI); err != nil { + return nil, gtserror.Newf("error setting id: %w", err) } - statusIDProp := streams.NewJSONLDIdProperty() - statusIDProp.SetIRI(statusURI) - status.SetJSONLDId(statusIDProp) - // type - // will be set automatically by go-fed + // `summary` property. + ap.AppendSummary(statusable, s.ContentWarning) - // summary aka cw - statusSummaryProp := streams.NewActivityStreamsSummaryProperty() - statusSummaryProp.AppendXMLSchemaString(s.ContentWarning) - status.SetActivityStreamsSummary(statusSummaryProp) - - // inReplyTo + // `inReplyTo` property. if s.InReplyToURI != "" { rURI, err := url.Parse(s.InReplyToURI) if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", s.InReplyToURI, err) + return nil, gtserror.Newf("error parsing inReplyTo: %w", err) } - - inReplyToProp := streams.NewActivityStreamsInReplyToProperty() - inReplyToProp.AppendIRI(rURI) - status.SetActivityStreamsInReplyTo(inReplyToProp) + ap.AppendInReplyTo(statusable, rURI) } - // Set created / updated at properties. - ap.SetPublished(status, s.CreatedAt) + // `published` and `updatedAt` properties. + ap.SetPublished(statusable, s.CreatedAt) if at := s.EditedAt; !at.IsZero() { - ap.SetUpdated(status, at) + ap.SetUpdated(statusable, at) } - // url + // Web-accessible `url` property. if s.URL != "" { sURL, err := url.Parse(s.URL) if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", s.URL, err) + return nil, gtserror.Newf("error parsing url: %w", err) } - - urlProp := streams.NewActivityStreamsUrlProperty() - urlProp.AppendIRI(sURL) - status.SetActivityStreamsUrl(urlProp) + ap.AppendURL(statusable, sURL) } - // attributedTo - authorAccountURI, err := url.Parse(s.Account.URI) + // `attributedTo` property. + acctURI, err := url.Parse(s.Account.URI) if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", s.Account.URI, err) + return nil, gtserror.Newf("error parsing account uri: %w", err) } - attributedToProp := streams.NewActivityStreamsAttributedToProperty() - attributedToProp.AppendIRI(authorAccountURI) - status.SetActivityStreamsAttributedTo(attributedToProp) + ap.AppendAttributedTo(statusable, acctURI) - // tags + // Start building out `tag` property. tagProp := streams.NewActivityStreamsTagProperty() - // tag -- mentions - mentions := s.Mentions - if len(s.MentionIDs) != len(mentions) { - mentions, err = c.state.DB.GetMentions(ctx, s.MentionIDs) - if err != nil { - return nil, gtserror.Newf("error getting mentions: %w", err) - } - } - for _, m := range mentions { + // `tag`: mentions + for _, m := range s.Mentions { asMention, err := c.MentionToAS(ctx, m) if err != nil { return nil, gtserror.Newf("error converting mention to AS mention: %w", err) @@ -583,139 +561,109 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat tagProp.AppendActivityStreamsMention(asMention) } - // tag -- emojis - emojis := s.Emojis - if len(s.EmojiIDs) != len(emojis) { - emojis, err = c.state.DB.GetEmojisByIDs(ctx, s.EmojiIDs) - if err != nil { - return nil, gtserror.Newf("error getting emojis from database: %w", err) - } - } - for _, emoji := range emojis { - asEmoji, err := c.EmojiToAS(ctx, emoji) + // `tag`: emojis + for _, e := range s.Emojis { + asEmoji, err := c.EmojiToAS(ctx, e) if err != nil { return nil, gtserror.Newf("error converting emoji to AS emoji: %w", err) } tagProp.AppendTootEmoji(asEmoji) } - // tag -- hashtags - hashtags := s.Tags - if len(s.TagIDs) != len(hashtags) { - hashtags, err = c.state.DB.GetTags(ctx, s.TagIDs) - if err != nil { - return nil, gtserror.Newf("error getting tags: %w", err) - } - } - for _, ht := range hashtags { - asHashtag, err := c.TagToAS(ctx, ht) + // `tag`: hashtags + for _, t := range s.Tags { + asHashtag, err := c.TagToAS(ctx, t) if err != nil { return nil, gtserror.Newf("error converting tag to AS tag: %w", err) } tagProp.AppendTootHashtag(asHashtag) } - status.SetActivityStreamsTag(tagProp) - // parse out some URIs we need here - authorFollowersURI, err := url.Parse(s.Account.FollowersURI) - if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", s.Account.FollowersURI, err) - } + // Append built `tag` property. + statusable.SetActivityStreamsTag(tagProp) - publicURI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, gtserror.Newf("error parsing url %s: %w", pub.PublicActivityPubIRI, err) - } + // `to` and `cc` properties + // depend on visibility of post. + if s.Visibility == gtsmodel.VisibilityDirect { + // If DIRECT visibility, then only mentioned + // users should be added to TO, nothing in CC. + for _, m := range s.Mentions { + iri, err := url.Parse(m.TargetAccount.URI) + if err != nil { + return nil, gtserror.Newf("error parsing mention target: %w", err) + } + ap.AppendTo(statusable, iri) + } - // to and cc - toProp := streams.NewActivityStreamsToProperty() - ccProp := streams.NewActivityStreamsCcProperty() - switch s.Visibility { - case gtsmodel.VisibilityDirect: - // if DIRECT, then only mentioned users should be added to TO, and nothing to CC - for _, m := range mentions { - iri, err := url.Parse(m.TargetAccount.URI) - if err != nil { - return nil, gtserror.Newf("error parsing uri %s: %w", m.TargetAccount.URI, err) - } - toProp.AppendIRI(iri) + } else { + // For all other visibilities + // we need the followers URI. + followersURI, err := url.Parse(s.Account.FollowersURI) + if err != nil { + return nil, gtserror.Newf("error parsing followers url: %w", err) } - case gtsmodel.VisibilityMutualsOnly: - // TODO - case gtsmodel.VisibilityFollowersOnly: - // if FOLLOWERS ONLY then we want to add followers to TO, and mentions to CC - toProp.AppendIRI(authorFollowersURI) - for _, m := range mentions { - iri, err := url.Parse(m.TargetAccount.URI) - if err != nil { - return nil, gtserror.Newf("error parsing uri %s: %w", m.TargetAccount.URI, err) - } - ccProp.AppendIRI(iri) + + switch s.Visibility { + // If FOLLOWERS ONLY visibility, then + // we want to add followers to TO. + case gtsmodel.VisibilityFollowersOnly: + ap.AppendTo(statusable, followersURI) + + // If UNLOCKED visibility, then + // we want to add followers to TO, + // with public in CC. + case gtsmodel.VisibilityUnlocked: + ap.AppendTo(statusable, followersURI) + ap.AppendCc(statusable, ap.PublicIRI()) + + // If PUBLIC visibility, then + // we want to add public to TO, + // with followers in CC. + case gtsmodel.VisibilityPublic: + ap.AppendTo(statusable, ap.PublicIRI()) + ap.AppendCc(statusable, followersURI) } - case gtsmodel.VisibilityUnlocked: - // if UNLOCKED, we want to add followers to TO, and public and mentions to CC - toProp.AppendIRI(authorFollowersURI) - ccProp.AppendIRI(publicURI) - for _, m := range mentions { + + // In all non-direct cases, + // mentioned accounts go in Cc. + for _, m := range s.Mentions { iri, err := url.Parse(m.TargetAccount.URI) if err != nil { return nil, gtserror.Newf("error parsing uri %s: %w", m.TargetAccount.URI, err) } - ccProp.AppendIRI(iri) - } - case gtsmodel.VisibilityPublic: - // if PUBLIC, we want to add public to TO, and followers and mentions to CC - toProp.AppendIRI(publicURI) - ccProp.AppendIRI(authorFollowersURI) - for _, m := range mentions { - iri, err := url.Parse(m.TargetAccount.URI) - if err != nil { - return nil, gtserror.Newf("error parsing uri %s: %w", m.TargetAccount.URI, err) - } - ccProp.AppendIRI(iri) + ap.AppendCc(statusable, iri) } } - status.SetActivityStreamsTo(toProp) - status.SetActivityStreamsCc(ccProp) - - // conversation - // TODO - - // content -- the actual post - // itself, plus the language - contentProp := streams.NewActivityStreamsContentProperty() - contentProp.AppendXMLSchemaString(s.Content) + // `content` and `contentMap` properties. + ap.AppendContent(statusable, s.Content) if s.Language != "" { - contentProp.AppendRDFLangString(map[string]string{ - s.Language: s.Content, - }) + ap.AppendContentMap( + statusable, + map[string]string{ + s.Language: s.Content, + }, + ) } - status.SetActivityStreamsContent(contentProp) - - // attachments - if err := c.attachAttachments(ctx, s, status); err != nil { + // `attachment` property. + if err := c.attachAttachments(ctx, s, statusable); err != nil { return nil, gtserror.Newf("error attaching attachments: %w", err) } - // replies - repliesCollection, err := c.StatusToASRepliesCollection(ctx, s, false) + // `replies` collection property. + // Todo: add `likes` and `shares` properties. + replies, err := c.StatusToASRepliesCollection(ctx, s, false) if err != nil { - return nil, fmt.Errorf("error creating repliesCollection: %w", err) + return nil, gtserror.Newf("error creating repliesCollection: %w", err) } + ap.SetReplies(statusable, replies) - repliesProp := streams.NewActivityStreamsRepliesProperty() - repliesProp.SetActivityStreamsCollection(repliesCollection) - status.SetActivityStreamsReplies(repliesProp) + // `sensitive` property. + ap.AppendSensitive(statusable, *s.Sensitive) - // sensitive - sensitiveProp := streams.NewActivityStreamsSensitiveProperty() - sensitiveProp.AppendXMLSchemaBoolean(*s.Sensitive) - status.SetActivityStreamsSensitive(sensitiveProp) - - // interactionPolicy - if ipa, ok := status.(ap.InteractionPolicyAware); ok { + // `interactionPolicy` property. + if wip, ok := statusable.(ap.WithInteractionPolicy); ok { var p *gtsmodel.InteractionPolicy if s.InteractionPolicy != nil { // Use InteractionPolicy @@ -728,28 +676,29 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat } policy, err := c.InteractionPolicyToASInteractionPolicy(ctx, p, s) if err != nil { - return nil, fmt.Errorf("error creating interactionPolicy: %w", err) + return nil, gtserror.Newf("error creating interactionPolicy: %w", err) } // Set interaction policy. policyProp := streams.NewGoToSocialInteractionPolicyProperty() policyProp.AppendGoToSocialInteractionPolicy(policy) - ipa.SetGoToSocialInteractionPolicy(policyProp) + wip.SetGoToSocialInteractionPolicy(policyProp) + } - // Parse + set approvedBy. - if s.ApprovedByURI != "" { - approvedBy, err := url.Parse(s.ApprovedByURI) - if err != nil { - return nil, fmt.Errorf("error parsing approvedBy: %w", err) - } + // `approvedBy` and/or `replyAuthorization` property. + if s.ApprovedByURI != "" { + err := c.appendASInteractionAuthorization( + ctx, + s.ApprovedByURI, + statusable, + ) - approvedByProp := streams.NewGoToSocialApprovedByProperty() - approvedByProp.Set(approvedBy) - ipa.SetGoToSocialApprovedBy(approvedByProp) + if err != nil { + return nil, gtserror.Newf("error setting reply authorization field(s): %w", err) } } - return status, nil + return statusable, nil } func (c *Converter) addPollToAS(poll *gtsmodel.Poll, dst ap.Pollable) error { @@ -875,10 +824,7 @@ func (c *Converter) StatusToASDelete(ctx context.Context, s *gtsmodel.Status) (v // At worst, a remote instance becomes aware of the // URI for a status which is now deleted anyway. if s.Visibility != gtsmodel.VisibilityDirect { - publicURI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, fmt.Errorf("StatusToASDelete: error parsing url %s: %w", pub.PublicActivityPubIRI, err) - } + publicURI := ap.PublicIRI() toProp.AppendIRI(publicURI) actorFollowersURI, err := url.Parse(s.Account.FollowersURI) @@ -1227,180 +1173,137 @@ func (c *Converter) attachAttachments( // FaveToAS converts a gts model status fave into an activityStreams LIKE, suitable for federation. // We want to end up with something like this: // -// { -// "@context": "https://www.w3.org/ns/activitystreams", -// "actor": "https://ondergrond.org/users/dumpsterqueer", -// "id": "https://ondergrond.org/users/dumpsterqueer#likes/44584", -// "object": "https://testingtesting123.xyz/users/gotosocial_test_account/statuses/771aea80-a33d-4d6d-8dfd-57d4d2bfcbd4", -// "type": "Like" -// } +// { +// "@context": "https://www.w3.org/ns/activitystreams", +// "actor": "https://ondergrond.org/users/dumpsterqueer", +// "id": "https://ondergrond.org/users/dumpsterqueer#likes/44584", +// "object": "https://testingtesting123.xyz/users/gotosocial_test_account/statuses/771aea80-a33d-4d6d-8dfd-57d4d2bfcbd4", +// "type": "Like" +// } func (c *Converter) FaveToAS(ctx context.Context, f *gtsmodel.StatusFave) (vocab.ActivityStreamsLike, error) { - // check if targetStatus is already pinned to this fave, and fetch it if not - if f.Status == nil { - s, err := c.state.DB.GetStatusByID(ctx, f.StatusID) - if err != nil { - return nil, fmt.Errorf("FaveToAS: error fetching target status from database: %s", err) - } - f.Status = s + // Ensure the status fave model is fully populated. + if err := c.state.DB.PopulateStatusFave(ctx, f); err != nil { + return nil, gtserror.Newf("error populating status fave: %w", err) } - // check if the targetAccount is already pinned to this fave, and fetch it if not - if f.TargetAccount == nil { - a, err := c.state.DB.GetAccountByID(ctx, f.TargetAccountID) - if err != nil { - return nil, fmt.Errorf("FaveToAS: error fetching target account from database: %s", err) - } - f.TargetAccount = a - } - - // check if the faving account is already pinned to this fave, and fetch it if not - if f.Account == nil { - a, err := c.state.DB.GetAccountByID(ctx, f.AccountID) - if err != nil { - return nil, fmt.Errorf("FaveToAS: error fetching faving account from database: %s", err) - } - f.Account = a - } - - // create the like + // Start building the Like. like := streams.NewActivityStreamsLike() - // set the actor property to the fave-ing account's URI - actorProp := streams.NewActivityStreamsActorProperty() + // `id` property. + if err := ap.SetJSONLDIdStr(like, f.URI); err != nil { + return nil, gtserror.Newf("error setting id: %w", err) + } + + // `actor` property is the faving account URI. actorIRI, err := url.Parse(f.Account.URI) if err != nil { - return nil, fmt.Errorf("FaveToAS: error parsing uri %s: %s", f.Account.URI, err) + return nil, gtserror.Newf("error parsing actor uri: %w", err) } - actorProp.AppendIRI(actorIRI) - like.SetActivityStreamsActor(actorProp) + ap.AppendActorIRIs(like, actorIRI) - // set the ID property to the fave's URI - idProp := streams.NewJSONLDIdProperty() - idIRI, err := url.Parse(f.URI) + // `object` property is the target status URI. + targetStatusIRI, err := url.Parse(f.Status.URI) if err != nil { - return nil, fmt.Errorf("FaveToAS: error parsing uri %s: %s", f.URI, err) + return nil, gtserror.Newf("error parsing status uri: %w", err) } - idProp.Set(idIRI) - like.SetJSONLDId(idProp) + ap.AppendObjectIRIs(like, targetStatusIRI) - // set the object property to the target status's URI - objectProp := streams.NewActivityStreamsObjectProperty() - statusIRI, err := url.Parse(f.Status.URI) - if err != nil { - return nil, fmt.Errorf("FaveToAS: error parsing uri %s: %s", f.Status.URI, err) - } - objectProp.AppendIRI(statusIRI) - like.SetActivityStreamsObject(objectProp) - - // set the TO property to the target account's IRI - toProp := streams.NewActivityStreamsToProperty() + // `to` is the owner of the target status. toIRI, err := url.Parse(f.TargetAccount.URI) if err != nil { - return nil, fmt.Errorf("FaveToAS: error parsing uri %s: %s", f.TargetAccount.URI, err) + return nil, gtserror.Newf("error parsing account uri: %w", err) } - toProp.AppendIRI(toIRI) - like.SetActivityStreamsTo(toProp) + ap.AppendTo(like, toIRI) - // Parse + set approvedBy. + // Parse + set authorization. if f.ApprovedByURI != "" { - approvedBy, err := url.Parse(f.ApprovedByURI) + err := c.appendASInteractionAuthorization( + ctx, + f.ApprovedByURI, + like, + ) if err != nil { - return nil, fmt.Errorf("error parsing approvedBy: %w", err) + return nil, gtserror.Newf("error setting like authorization field(s): %w", err) } - - approvedByProp := streams.NewGoToSocialApprovedByProperty() - approvedByProp.Set(approvedBy) - like.SetGoToSocialApprovedBy(approvedByProp) } return like, nil } -// BoostToAS converts a gts model boost into an activityStreams ANNOUNCE, suitable for federation -func (c *Converter) BoostToAS(ctx context.Context, boostWrapperStatus *gtsmodel.Status, boostingAccount *gtsmodel.Account, boostedAccount *gtsmodel.Account) (vocab.ActivityStreamsAnnounce, error) { - // the boosted status is probably pinned to the boostWrapperStatus but double check to make sure - if boostWrapperStatus.BoostOf == nil { - b, err := c.state.DB.GetStatusByID(ctx, boostWrapperStatus.BoostOfID) - if err != nil { - return nil, fmt.Errorf("BoostToAS: error getting status with ID %s from the db: %s", boostWrapperStatus.BoostOfID, err) - } - boostWrapperStatus.BoostOf = b +// BoostToAS converts a *gtsmodel.Status boost wrapper into +// an ActivityStreams Announce activity, suitable for federation. +// +// Result will look something like: +// +// { +// "@context": "https://www.w3.org/ns/activitystreams", +// "actor": "http://localhost:8080/users/the_mighty_zork", +// "cc": "http://localhost:8080/users/the_mighty_zork", +// "id": "http://localhost:8080/users/the_mighty_zork/statuses/01G74JJ1KS331G2JXHRMZCE0ER", +// "object": "http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS", +// "published": "2022-06-09T13:12:00Z", +// "to": "http://localhost:8080/users/the_mighty_zork/followers", +// "type": "Announce" +// } +func (c *Converter) BoostToAS(ctx context.Context, bw *gtsmodel.Status) (vocab.ActivityStreamsAnnounce, error) { + // Ensure the status model is fully populated. + if err := c.state.DB.PopulateStatus(ctx, bw); err != nil { + return nil, gtserror.Newf("error populating boost wrapper status: %w", err) } - // create the announce + // Start building the Announce. announce := streams.NewActivityStreamsAnnounce() - // set the actor - boosterURI, err := url.Parse(boostingAccount.URI) - if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostingAccount.URI, err) + // `id` property. + if err := ap.SetJSONLDIdStr(announce, bw.URI); err != nil { + return nil, gtserror.Newf("error setting id: %w", err) } - actorProp := streams.NewActivityStreamsActorProperty() - actorProp.AppendIRI(boosterURI) - announce.SetActivityStreamsActor(actorProp) - // set the ID - boostIDURI, err := url.Parse(boostWrapperStatus.URI) + // `actor` property. + actorURI, err := url.Parse(bw.AccountURI) if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostWrapperStatus.URI, err) + return nil, fmt.Errorf("error parsing actor uri: %s", err) } - idProp := streams.NewJSONLDIdProperty() - idProp.SetIRI(boostIDURI) - announce.SetJSONLDId(idProp) + ap.AppendActorIRIs(announce, actorURI) - // set the object - boostedStatusURI, err := url.Parse(boostWrapperStatus.BoostOf.URI) + // `object` property is the target status URI. + boostTargetURI, err := url.Parse(bw.BoostOf.URI) if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostWrapperStatus.BoostOf.URI, err) + return nil, fmt.Errorf("error parsing target status uri: %s", err) } - objectProp := streams.NewActivityStreamsObjectProperty() - objectProp.AppendIRI(boostedStatusURI) - announce.SetActivityStreamsObject(objectProp) + ap.AppendObjectIRIs(announce, boostTargetURI) - // set the published time - publishedProp := streams.NewActivityStreamsPublishedProperty() - publishedProp.Set(boostWrapperStatus.CreatedAt) - announce.SetActivityStreamsPublished(publishedProp) + // `published` property is the time of the boost. + ap.SetPublished(announce, bw.CreatedAt) - // set the to - followersURI, err := url.Parse(boostingAccount.FollowersURI) + // `to` property. + followersURI, err := url.Parse(bw.Account.FollowersURI) if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostingAccount.FollowersURI, err) + return nil, fmt.Errorf("error parsing followers URI: %s", err) } - toProp := streams.NewActivityStreamsToProperty() - toProp.AppendIRI(followersURI) - announce.SetActivityStreamsTo(toProp) + ap.AppendTo(announce, followersURI) - // set the cc - ccProp := streams.NewActivityStreamsCcProperty() - boostedAccountURI, err := url.Parse(boostedAccount.URI) + // `cc` property. + boostedAccountURI, err := url.Parse(bw.BoostOfAccount.URI) if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostedAccount.URI, err) + return nil, fmt.Errorf("error parsing target account URI: %s", err) } - ccProp.AppendIRI(boostedAccountURI) + ap.AppendCc(announce, boostedAccountURI) - // maybe CC it to public depending on the boosted status visibility - switch boostWrapperStatus.BoostOf.Visibility { + // `cc` should include public if + // this is a public or unlocked boost. + switch bw.BoostOf.Visibility { case gtsmodel.VisibilityPublic, gtsmodel.VisibilityUnlocked: - publicURI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", pub.PublicActivityPubIRI, err) - } - ccProp.AppendIRI(publicURI) + ap.AppendCc(announce, ap.PublicIRI()) } - announce.SetActivityStreamsCc(ccProp) - - // Parse + set approvedBy. - if boostWrapperStatus.ApprovedByURI != "" { - approvedBy, err := url.Parse(boostWrapperStatus.ApprovedByURI) + // Parse + set authorization. + if bw.ApprovedByURI != "" { + approvedBy, err := url.Parse(bw.ApprovedByURI) if err != nil { return nil, fmt.Errorf("error parsing approvedBy: %w", err) } - - approvedByProp := streams.NewGoToSocialApprovedByProperty() - approvedByProp.Set(approvedBy) - announce.SetGoToSocialApprovedBy(approvedByProp) + ap.SetApprovedBy(announce, approvedBy) } return announce, nil @@ -2172,7 +2075,7 @@ func (c *Converter) InteractionReqToASAccept( ) (vocab.ActivityStreamsAccept, error) { accept := streams.NewActivityStreamsAccept() - acceptID, err := url.Parse(req.URI) + acceptID, err := url.Parse(req.ResponseURI) if err != nil { return nil, gtserror.Newf("invalid accept uri: %w", err) } @@ -2187,14 +2090,14 @@ func (c *Converter) InteractionReqToASAccept( return nil, gtserror.Newf("invalid object uri: %w", err) } - if req.Status == nil { - req.Status, err = c.state.DB.GetStatusByID(ctx, req.StatusID) + if req.TargetStatus == nil { + req.TargetStatus, err = c.state.DB.GetStatusByID(ctx, req.TargetStatusID) if err != nil { return nil, gtserror.Newf("db error getting interaction req target status: %w", err) } } - targetIRI, err := url.Parse(req.Status.URI) + targetIRI, err := url.Parse(req.TargetStatus.URI) if err != nil { return nil, gtserror.Newf("invalid interaction req target status uri: %w", err) } @@ -2204,35 +2107,99 @@ func (c *Converter) InteractionReqToASAccept( return nil, gtserror.Newf("invalid interacting account uri: %w", err) } - // Set id to the URI of - // interaction request. + // Set id. ap.SetJSONLDId(accept, acceptID) - // Actor is the account that - // owns the approval / accept. + // Actor is the account + // Accepting the interaction. ap.AppendActorIRIs(accept, actorIRI) - // Object is the interaction URI. - ap.AppendObjectIRIs(accept, objectIRI) + polite := req.IsPolite() + if polite { + // If accepting a polite request, put + // a barebones version of the *Request + // in the `object` property. + var ( + objProp = streams.NewActivityStreamsObjectProperty() + ir ap.InteractionRequestable + ) + switch req.InteractionType { + case gtsmodel.InteractionLike: + v := streams.NewGoToSocialLikeRequest() + objProp.AppendGoToSocialLikeRequest(v) + ir = v + case gtsmodel.InteractionReply: + v := streams.NewGoToSocialReplyRequest() + objProp.AppendGoToSocialReplyRequest(v) + ir = v + case gtsmodel.InteractionAnnounce: + v := streams.NewGoToSocialAnnounceRequest() + objProp.AppendGoToSocialAnnounceRequest(v) + ir = v + } - // Target is the URI of the - // status being interacted with. - ap.AppendTargetIRIs(accept, targetIRI) + // URI of the interaction request. + if err := ap.SetJSONLDIdStr(ir, req.InteractionRequestURI); err != nil { + return nil, err + } + + // URI of the interacting actor. + ap.AppendActorIRIs(ir, toIRI) + + // URI of the status. + ap.AppendObjectIRIs(ir, targetIRI) + + // URI of the interaction. + ap.AppendInstrumentIRIs(ir, objectIRI) + + // Set the thing. + accept.SetActivityStreamsObject(objProp) + + // If polite, also include the "result" URI + // of the interaction Authorization object. + resultIRI, err := url.Parse(req.AuthorizationURI) + if err != nil { + return nil, gtserror.Newf("invalid authorization uri: %w", err) + } + ap.AppendResultIRIs(accept, resultIRI) + + } else { + // If accepting an impolite request, just set + // interaction URI as object and target status + // IRI as target. Don't give authorization in + // result field, as this will confuse pre v0.20.0 + // instances who don't understand Auth types yet. + // + // TODO: remove this path in v0.21.0 and send an + // accept of a Request for impolite requests too. + ap.AppendObjectIRIs(accept, objectIRI) + ap.AppendTargetIRIs(accept, targetIRI) + } // Address to the owner // of interaction URI. ap.AppendTo(accept, toIRI) - // Whether or not we cc this Accept to - // followers and public depends on the - // type of interaction it Accepts. + // If the request is polite, send + // the Accept only to the requester, + // no need to cc anything. + if polite { + return accept, nil + } + + // If the request was impolite, it's + // helpful for federation to distribute + // the Accept to our followers as well, + // depending on the type of interaction. var cc bool switch req.InteractionType { case gtsmodel.InteractionLike: // Accept of Like doesn't get cc'd - // because it's not that important. + // because it's not that important, + // as Likes are usually only ever + // sent to the post author. case gtsmodel.InteractionReply: // Accept of reply gets cc'd. @@ -2244,10 +2211,7 @@ func (c *Converter) InteractionReqToASAccept( } if cc { - publicIRI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, gtserror.Newf("invalid public uri: %w", err) - } + publicIRI := ap.PublicIRI() followersIRI, err := url.Parse(req.TargetAccount.FollowersURI) if err != nil { @@ -2268,7 +2232,7 @@ func (c *Converter) InteractionReqToASReject( ) (vocab.ActivityStreamsReject, error) { reject := streams.NewActivityStreamsReject() - rejectID, err := url.Parse(req.URI) + rejectID, err := url.Parse(req.ResponseURI) if err != nil { return nil, gtserror.Newf("invalid reject uri: %w", err) } @@ -2283,14 +2247,14 @@ func (c *Converter) InteractionReqToASReject( return nil, gtserror.Newf("invalid object uri: %w", err) } - if req.Status == nil { - req.Status, err = c.state.DB.GetStatusByID(ctx, req.StatusID) + if req.TargetStatus == nil { + req.TargetStatus, err = c.state.DB.GetStatusByID(ctx, req.TargetStatusID) if err != nil { return nil, gtserror.Newf("db error getting interaction req target status: %w", err) } } - targetIRI, err := url.Parse(req.Status.URI) + targetIRI, err := url.Parse(req.TargetStatus.URI) if err != nil { return nil, gtserror.Newf("invalid interaction req target status uri: %w", err) } @@ -2300,28 +2264,80 @@ func (c *Converter) InteractionReqToASReject( return nil, gtserror.Newf("invalid interacting account uri: %w", err) } - // Set id to the URI of - // interaction request. + // Set id. ap.SetJSONLDId(reject, rejectID) - // Actor is the account that - // owns the approval / reject. + // Actor is the account + // Rejecting the interaction. ap.AppendActorIRIs(reject, actorIRI) - // Object is the interaction URI. - ap.AppendObjectIRIs(reject, objectIRI) + polite := req.IsPolite() + if polite { + // If rejecting a polite request, put + // a barebones version of the *Request + // in the `object` property. + var ( + objProp = streams.NewActivityStreamsObjectProperty() + ir ap.InteractionRequestable + ) + switch req.InteractionType { + case gtsmodel.InteractionLike: + v := streams.NewGoToSocialLikeRequest() + objProp.AppendGoToSocialLikeRequest(v) + ir = v + case gtsmodel.InteractionReply: + v := streams.NewGoToSocialReplyRequest() + objProp.AppendGoToSocialReplyRequest(v) + ir = v + case gtsmodel.InteractionAnnounce: + v := streams.NewGoToSocialAnnounceRequest() + objProp.AppendGoToSocialAnnounceRequest(v) + ir = v + } - // Target is the URI of the - // status being interacted with. - ap.AppendTargetIRIs(reject, targetIRI) + // URI of the interaction request. + if err := ap.SetJSONLDIdStr(ir, req.InteractionRequestURI); err != nil { + return nil, err + } + + // URI of the interacting actor. + ap.AppendActorIRIs(ir, toIRI) + + // URI of the status. + ap.AppendObjectIRIs(ir, targetIRI) + + // URI of the interaction. + ap.AppendInstrumentIRIs(ir, objectIRI) + + // Set the thing. + reject.SetActivityStreamsObject(objProp) + + } else { + // If rejecting an impolite request, just set + // interaction URI as object and target status + // IRI as target. + // + // TODO: remove this path in v0.21.0 and send a + // Reject of a Request for impolite requests too. + ap.AppendObjectIRIs(reject, objectIRI) + ap.AppendTargetIRIs(reject, targetIRI) + } // Address to the owner // of interaction URI. ap.AppendTo(reject, toIRI) - // Whether or not we cc this Reject to - // followers and public depends on the - // type of interaction it Rejects. + // If the request is polite, send + // the Reject only to the requester, + // no need to cc anything. + if polite { + return reject, nil + } + + // If the request was impolite, it's + // helpful for federation to distribute + // the Reject to our followers as well, + // depending on the type of interaction. var cc bool switch req.InteractionType { @@ -2340,10 +2356,7 @@ func (c *Converter) InteractionReqToASReject( } if cc { - publicIRI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, gtserror.Newf("invalid public uri: %w", err) - } + publicIRI := ap.PublicIRI() followersIRI, err := url.Parse(req.TargetAccount.FollowersURI) if err != nil { @@ -2355,3 +2368,136 @@ func (c *Converter) InteractionReqToASReject( return reject, nil } + +// InteractionReqToASAuthorization converts an approved *gtsmodel.InteractionRequest +// to a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization object. +// +// End result will look something like this: +// +// { +// "@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" +// } +func (c *Converter) InteractionReqToASAuthorization( + ctx context.Context, + req *gtsmodel.InteractionRequest, +) (ap.Authorizationable, error) { + if !req.IsAccepted() { + const text = "cannot convert not-accepted interaction request to Authorization type" + return nil, gtserror.New(text) + } + + if err := c.state.DB.PopulateInteractionRequest(ctx, req); err != nil { + return nil, gtserror.Newf("error populating interaction request: %w", err) + } + + var auth ap.Authorizationable + switch req.InteractionType { + case gtsmodel.InteractionLike: + auth = streams.NewGoToSocialLikeAuthorization() + case gtsmodel.InteractionReply: + auth = streams.NewGoToSocialReplyAuthorization() + case gtsmodel.InteractionAnnounce: + auth = streams.NewGoToSocialAnnounceAuthorization() + } + + // Set the ID. + if err := ap.SetJSONLDIdStr(auth, req.AuthorizationURI); err != nil { + return nil, err + } + + // Set attributed to actor URI. + attributedToURI, err := url.Parse(req.TargetAccount.URI) + if err != nil { + return nil, gtserror.Newf("invalid target account URI: %w", err) + } + ap.AppendAttributedTo(auth, attributedToURI) + + // Set interaction URI (eg., uri of the fave, reply, or announce). + intObjURI, err := url.Parse(req.InteractionURI) + if err != nil { + return nil, gtserror.Newf("invalid interaction URI: %w", err) + } + ap.AppendInteractingObject(auth, intObjURI) + + // Set interaction target URI (ie., uri of the status interacted with). + intTargetURI, err := url.Parse(req.TargetStatus.URI) + if err != nil { + return nil, gtserror.Newf("invalid interaction target URI: %w", err) + } + ap.AppendInteractionTarget(auth, intTargetURI) + + return auth, nil +} + +// appendASInteractionAuthorization is a utility function +// that sets `approvedBy`, and `likeAuthorization`, +// `replyAuthorization`, or `announceAuthorization`. +func (c *Converter) appendASInteractionAuthorization( + ctx context.Context, + approvedByURIStr string, + t vocab.Type, +) error { + // ApprovedByURI is the URI of an + // Authorization for this interaction. + approvedByURI, err := url.Parse(approvedByURIStr) + if err != nil { + return gtserror.Newf("error parsing approvedByURIStr: %w", err) + } + + // Fetch relevant approved interaction + // request for this approvedByURIStr. + intReq, err := c.state.DB.GetInteractionRequestByAuthorizationURI( + gtscontext.SetBarebones(ctx), + approvedByURIStr, + ) + if err != nil { + return gtserror.Newf("db error checking for int req: %w", err) + } + + // Make sure it's actually accepted. + if !intReq.IsAccepted() { + return gtserror.Newf( + "approvedByURIStr %s corresponded to not-accepted interaction request %s", + approvedByURIStr, intReq.ID, + ) + } + + // Deprecated: Set `approvedBy` + // property to URI of the Accept. + // + // Todo: Remove this in v0.21.0. + if wap, ok := t.(ap.WithApprovedBy); ok { + responseURI, err := url.Parse(intReq.ResponseURI) + if err != nil { + return gtserror.Newf("error parsing responseURI: %w", err) + } + ap.SetApprovedBy(wap, responseURI) + } + + // Set the appropriate authorization + // property depending on type. + switch intReq.InteractionType { + case gtsmodel.InteractionLike: + if wla, ok := t.(ap.WithLikeAuthorization); ok { + ap.SetLikeAuthorization(wla, approvedByURI) + } + case gtsmodel.InteractionReply: + if wra, ok := t.(ap.WithReplyAuthorization); ok { + ap.SetReplyAuthorization(wra, approvedByURI) + } + case gtsmodel.InteractionAnnounce: + if waa, ok := t.(ap.WithAnnounceAuthorization); ok { + ap.SetAnnounceAuthorization(waa, approvedByURI) + } + } + + return nil +} diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go index 5c3e52ddb..970e16cfa 100644 --- a/internal/typeutils/internaltoas_test.go +++ b/internal/typeutils/internaltoas_test.go @@ -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)) } diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index b2a4652d3..961e99206 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -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 } diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go index 47ad284e6..5d066f410 100644 --- a/internal/typeutils/internaltofrontend_test.go +++ b/internal/typeutils/internaltofrontend_test.go @@ -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", diff --git a/internal/typeutils/wrap.go b/internal/typeutils/wrap.go index 59c7e2264..ae83ea4c7 100644 --- a/internal/typeutils/wrap.go +++ b/internal/typeutils/wrap.go @@ -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)) diff --git a/internal/uris/uri.go b/internal/uris/uri.go index d7ae9fe75..1a5ed7fbf 100644 --- a/internal/uris/uri.go +++ b/internal/uris/uri.go @@ -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 { diff --git a/testrig/testmodels.go b/testrig/testmodels.go index b7d527010..256107b80 100644 --- a/testrig/testmodels.go +++ b/testrig/testmodels.go @@ -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"), - `

hi @admin here's some media for ya, @the_mighty_zork you might like this too

`, - "

some unknown media included

", - 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: `

hi @admin here's some media for ya, @the_mighty_zork you might like this too

`, + Summary: "

some unknown media included

", + 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"), - "

Babe are you okay, you've hardly touched your #piss

", - "", - 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: `

@foss_satanBabe are you okay, you've hardly touched your #piss

`, + 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"), - `

@the_mighty_zork nice there it is:

social.pixie.town/users/f0x/st

`, - "", - 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: `

@the_mighty_zork nice there it is:

social.pixie.town/users/f0x/st

`, + 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) diff --git a/vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go b/vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go index 0eb116f40..6caf143f8 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/gen_consts.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/gen_init.go b/vendor/code.superseriousbusiness.org/activity/streams/gen_init.go index e837355d9..b34f706b7 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/gen_init.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/gen_init.go @@ -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) diff --git a/vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go b/vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go index 90a6b33c7..b181e858c 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/gen_manager.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/gen_pkg_gotosocial_property_constructors.go b/vendor/code.superseriousbusiness.org/activity/streams/gen_pkg_gotosocial_property_constructors.go index c4cd38bba..af56d3bb9 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/gen_pkg_gotosocial_property_constructors.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/gen_pkg_gotosocial_property_constructors.go @@ -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() +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_pkg.go index 7ecd4121b..924cec939 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_type_activitystreams_announce.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_type_activitystreams_announce.go index 0851dfa94..9906fdd49 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_type_activitystreams_announce.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_announce/gen_type_activitystreams_announce.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_pkg.go index e3ebfdb94..bba914f0a 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_type_activitystreams_article.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_type_activitystreams_article.go index 8a0229af7..3de164802 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_type_activitystreams_article.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_article/gen_type_activitystreams_article.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_pkg.go index 729435fbd..aaaa194c7 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_type_activitystreams_audio.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_type_activitystreams_audio.go index bb6664c2c..5b633801f 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_type_activitystreams_audio.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_audio/gen_type_activitystreams_audio.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_pkg.go index 98036d6d1..c3e4665df 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_type_activitystreams_document.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_type_activitystreams_document.go index 0d2d06780..f7d823984 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_type_activitystreams_document.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_document/gen_type_activitystreams_document.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_pkg.go index 6ec762ae5..c6760f1a6 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_type_activitystreams_event.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_type_activitystreams_event.go index 1ce5e55ba..e7de9773b 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_type_activitystreams_event.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_event/gen_type_activitystreams_event.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_pkg.go index 4ab62e8ae..b3bcc10c6 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_type_activitystreams_image.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_type_activitystreams_image.go index 23274172e..b5f446d62 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_type_activitystreams_image.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_image/gen_type_activitystreams_image.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_pkg.go index 2c681db43..f27026614 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_type_activitystreams_like.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_type_activitystreams_like.go index f1f0ac6a7..d2aed32e3 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_type_activitystreams_like.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_like/gen_type_activitystreams_like.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_pkg.go index 31280fdfd..b340c14b4 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_type_activitystreams_note.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_type_activitystreams_note.go index 15989dd87..dcb24a081 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_type_activitystreams_note.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_note/gen_type_activitystreams_note.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_pkg.go index 6ea71e27e..2e1119eb0 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_type_activitystreams_page.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_type_activitystreams_page.go index 2ba55241d..13f6b40d0 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_type_activitystreams_page.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_page/gen_type_activitystreams_page.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_pkg.go index e87a1ca33..2821f74c5 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_type_activitystreams_place.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_type_activitystreams_place.go index 2c7f96e8d..34d0c90f9 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_type_activitystreams_place.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_place/gen_type_activitystreams_place.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_pkg.go index dbd20143d..4f01c913a 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_type_activitystreams_profile.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_type_activitystreams_profile.go index 7eed51390..6881acc18 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_type_activitystreams_profile.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_profile/gen_type_activitystreams_profile.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_pkg.go index f2ce80982..76fb4bc0c 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_type_activitystreams_question.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_type_activitystreams_question.go index f2ef016f1..61fc6ab5f 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_type_activitystreams_question.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_question/gen_type_activitystreams_question.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_pkg.go index b03980b2a..91317d98c 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_pkg.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_pkg.go @@ -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" diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_type_activitystreams_video.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_type_activitystreams_video.go index c8a93e70f..d27f1652d 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_type_activitystreams_video.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/activitystreams/type_video/gen_type_activitystreams_video.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_doc.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_doc.go new file mode 100644 index 000000000..ace6a9aaa --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_doc.go @@ -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 diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_pkg.go new file mode 100644 index 000000000..2271a5813 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_pkg.go @@ -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 +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_property_gotosocial_announceAuthorization.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_property_gotosocial_announceAuthorization.go new file mode 100644 index 000000000..dcd897abd --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization/gen_property_gotosocial_announceAuthorization.go @@ -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) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_doc.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_doc.go new file mode 100644 index 000000000..bbb41f098 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_doc.go @@ -0,0 +1,17 @@ +// Code generated by astool. DO NOT EDIT. + +// Package propertylikeauthorization contains the implementation for the +// likeAuthorization 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 propertylikeauthorization diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_pkg.go new file mode 100644 index 000000000..c2540aed5 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_pkg.go @@ -0,0 +1,15 @@ +// Code generated by astool. DO NOT EDIT. + +package propertylikeauthorization + +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 +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_property_gotosocial_likeAuthorization.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_property_gotosocial_likeAuthorization.go new file mode 100644 index 000000000..d98c3d96f --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization/gen_property_gotosocial_likeAuthorization.go @@ -0,0 +1,182 @@ +// Code generated by astool. DO NOT EDIT. + +package propertylikeauthorization + +import ( + anyuri "code.superseriousbusiness.org/activity/streams/values/anyURI" + vocab "code.superseriousbusiness.org/activity/streams/vocab" + "fmt" + "net/url" +) + +// GoToSocialLikeAuthorizationProperty is the functional property +// "likeAuthorization". It is permitted to be a single nilable value type. +type GoToSocialLikeAuthorizationProperty struct { + xmlschemaAnyURIMember *url.URL + unknown interface{} + alias string +} + +// DeserializeLikeAuthorizationProperty creates a "likeAuthorization" property +// from an interface representation that has been unmarshalled from a text or +// binary format. +func DeserializeLikeAuthorizationProperty(m map[string]interface{}, aliasMap map[string]string) (*GoToSocialLikeAuthorizationProperty, error) { + alias := "" + if a, ok := aliasMap["https://gotosocial.org/ns"]; ok { + alias = a + } + propName := "likeAuthorization" + if len(alias) > 0 { + // Use alias both to find the property, and set within the property. + propName = fmt.Sprintf("%s:%s", alias, "likeAuthorization") + } + i, ok := m[propName] + + if ok { + if v, err := anyuri.DeserializeAnyURI(i); err == nil { + this := &GoToSocialLikeAuthorizationProperty{ + alias: alias, + xmlschemaAnyURIMember: v, + } + return this, nil + } + this := &GoToSocialLikeAuthorizationProperty{ + alias: alias, + unknown: i, + } + return this, nil + } + return nil, nil +} + +// NewGoToSocialLikeAuthorizationProperty creates a new likeAuthorization property. +func NewGoToSocialLikeAuthorizationProperty() *GoToSocialLikeAuthorizationProperty { + return &GoToSocialLikeAuthorizationProperty{alias: ""} +} + +// Clear ensures no value of this property is set. Calling IsXMLSchemaAnyURI +// afterwards will return false. +func (this *GoToSocialLikeAuthorizationProperty) 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 GoToSocialLikeAuthorizationProperty) 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 GoToSocialLikeAuthorizationProperty) GetIRI() *url.URL { + return this.xmlschemaAnyURIMember +} + +// HasAny returns true if the value or IRI is set. +func (this GoToSocialLikeAuthorizationProperty) HasAny() bool { + return this.IsXMLSchemaAnyURI() +} + +// IsIRI returns true if this property is an IRI. +func (this GoToSocialLikeAuthorizationProperty) IsIRI() bool { + return this.xmlschemaAnyURIMember != nil +} + +// IsXMLSchemaAnyURI returns true if this property is set and not an IRI. +func (this GoToSocialLikeAuthorizationProperty) 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 GoToSocialLikeAuthorizationProperty) 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 GoToSocialLikeAuthorizationProperty) 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 GoToSocialLikeAuthorizationProperty) LessThan(o vocab.GoToSocialLikeAuthorizationProperty) 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: "likeAuthorization". +func (this GoToSocialLikeAuthorizationProperty) Name() string { + if len(this.alias) > 0 { + return this.alias + ":" + "likeAuthorization" + } else { + return "likeAuthorization" + } +} + +// 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 GoToSocialLikeAuthorizationProperty) 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 *GoToSocialLikeAuthorizationProperty) Set(v *url.URL) { + this.Clear() + this.xmlschemaAnyURIMember = v +} + +// SetIRI sets the value of this property. Calling IsIRI afterwards will return +// true. +func (this *GoToSocialLikeAuthorizationProperty) SetIRI(v *url.URL) { + this.Clear() + this.Set(v) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_doc.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_doc.go new file mode 100644 index 000000000..5ff0ca45d --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_doc.go @@ -0,0 +1,17 @@ +// Code generated by astool. DO NOT EDIT. + +// Package propertyreplyauthorization contains the implementation for the +// replyAuthorization 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 propertyreplyauthorization diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_pkg.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_pkg.go new file mode 100644 index 000000000..a23c898d2 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_pkg.go @@ -0,0 +1,15 @@ +// Code generated by astool. DO NOT EDIT. + +package propertyreplyauthorization + +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 +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_property_gotosocial_replyAuthorization.go b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_property_gotosocial_replyAuthorization.go new file mode 100644 index 000000000..235d86b97 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization/gen_property_gotosocial_replyAuthorization.go @@ -0,0 +1,183 @@ +// Code generated by astool. DO NOT EDIT. + +package propertyreplyauthorization + +import ( + anyuri "code.superseriousbusiness.org/activity/streams/values/anyURI" + vocab "code.superseriousbusiness.org/activity/streams/vocab" + "fmt" + "net/url" +) + +// GoToSocialReplyAuthorizationProperty is the functional property +// "replyAuthorization". It is permitted to be a single nilable value type. +type GoToSocialReplyAuthorizationProperty struct { + xmlschemaAnyURIMember *url.URL + unknown interface{} + alias string +} + +// DeserializeReplyAuthorizationProperty creates a "replyAuthorization" property +// from an interface representation that has been unmarshalled from a text or +// binary format. +func DeserializeReplyAuthorizationProperty(m map[string]interface{}, aliasMap map[string]string) (*GoToSocialReplyAuthorizationProperty, error) { + alias := "" + if a, ok := aliasMap["https://gotosocial.org/ns"]; ok { + alias = a + } + propName := "replyAuthorization" + if len(alias) > 0 { + // Use alias both to find the property, and set within the property. + propName = fmt.Sprintf("%s:%s", alias, "replyAuthorization") + } + i, ok := m[propName] + + if ok { + if v, err := anyuri.DeserializeAnyURI(i); err == nil { + this := &GoToSocialReplyAuthorizationProperty{ + alias: alias, + xmlschemaAnyURIMember: v, + } + return this, nil + } + this := &GoToSocialReplyAuthorizationProperty{ + alias: alias, + unknown: i, + } + return this, nil + } + return nil, nil +} + +// NewGoToSocialReplyAuthorizationProperty creates a new replyAuthorization +// property. +func NewGoToSocialReplyAuthorizationProperty() *GoToSocialReplyAuthorizationProperty { + return &GoToSocialReplyAuthorizationProperty{alias: ""} +} + +// Clear ensures no value of this property is set. Calling IsXMLSchemaAnyURI +// afterwards will return false. +func (this *GoToSocialReplyAuthorizationProperty) 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 GoToSocialReplyAuthorizationProperty) 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 GoToSocialReplyAuthorizationProperty) GetIRI() *url.URL { + return this.xmlschemaAnyURIMember +} + +// HasAny returns true if the value or IRI is set. +func (this GoToSocialReplyAuthorizationProperty) HasAny() bool { + return this.IsXMLSchemaAnyURI() +} + +// IsIRI returns true if this property is an IRI. +func (this GoToSocialReplyAuthorizationProperty) IsIRI() bool { + return this.xmlschemaAnyURIMember != nil +} + +// IsXMLSchemaAnyURI returns true if this property is set and not an IRI. +func (this GoToSocialReplyAuthorizationProperty) 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 GoToSocialReplyAuthorizationProperty) 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 GoToSocialReplyAuthorizationProperty) 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 GoToSocialReplyAuthorizationProperty) LessThan(o vocab.GoToSocialReplyAuthorizationProperty) 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: "replyAuthorization". +func (this GoToSocialReplyAuthorizationProperty) Name() string { + if len(this.alias) > 0 { + return this.alias + ":" + "replyAuthorization" + } else { + return "replyAuthorization" + } +} + +// 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 GoToSocialReplyAuthorizationProperty) 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 *GoToSocialReplyAuthorizationProperty) Set(v *url.URL) { + this.Clear() + this.xmlschemaAnyURIMember = v +} + +// SetIRI sets the value of this property. Calling IsIRI afterwards will return +// true. +func (this *GoToSocialReplyAuthorizationProperty) SetIRI(v *url.URL) { + this.Clear() + this.Set(v) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_announceAuthorization_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_announceAuthorization_interface.go new file mode 100644 index 000000000..f9542d827 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_announceAuthorization_interface.go @@ -0,0 +1,53 @@ +// Code generated by astool. DO NOT EDIT. + +package vocab + +import "net/url" + +// URI/ID of an AnnounceAuthorization permitting the Announce this property is +// attached to. +type GoToSocialAnnounceAuthorizationProperty interface { + // Clear ensures no value of this property is set. Calling + // IsXMLSchemaAnyURI afterwards will return false. + Clear() + // Get returns the value of this property. When IsXMLSchemaAnyURI returns + // false, Get will return any arbitrary value. + Get() *url.URL + // GetIRI returns the IRI of this property. When IsIRI returns false, + // GetIRI will return any arbitrary value. + GetIRI() *url.URL + // HasAny returns true if the value or IRI is set. + HasAny() bool + // IsIRI returns true if this property is an IRI. + IsIRI() bool + // IsXMLSchemaAnyURI returns true if this property is set and not an IRI. + IsXMLSchemaAnyURI() bool + // 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. + JSONLDContext() map[string]string + // 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. + KindIndex() int + // 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. + LessThan(o GoToSocialAnnounceAuthorizationProperty) bool + // Name returns the name of this property: "announceAuthorization". + Name() string + // 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. + Serialize() (interface{}, error) + // Set sets the value of this property. Calling IsXMLSchemaAnyURI + // afterwards will return true. + Set(v *url.URL) + // SetIRI sets the value of this property. Calling IsIRI afterwards will + // return true. + SetIRI(v *url.URL) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_approvedBy_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_approvedBy_interface.go index c99467246..86a98f638 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_approvedBy_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_approvedBy_interface.go @@ -4,11 +4,12 @@ package vocab import "net/url" -// URI/ID of an Accept Activity or approval, which itself points towards the ID of -// the Activity or Object to which this property is attached. The presence of -// this property on an Activity or Object indicates that an interaction has -// been Approve'd by the Actor whose Object this Activity or Object interacts -// with. +// DEPRECATED: Use `likeAuthorization`, `replyAuthorization`, or +// `announceAuthorization` instead. URI/ID of an Accept Activity or approval, +// which itself points towards the ID of the Activity or Object to which this +// property is attached. The presence of this property on an Activity or +// Object indicates that an interaction has been Approve'd by the Actor whose +// Object this Activity or Object interacts with. type GoToSocialApprovedByProperty interface { // Clear ensures no value of this property is set. Calling // IsXMLSchemaAnyURI afterwards will return false. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesCcPublicFromUnauthedWeb_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesCcPublicFromUnauthedWeb_interface.go index a84a2a366..8019bd142 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesCcPublicFromUnauthedWeb_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesCcPublicFromUnauthedWeb_interface.go @@ -8,8 +8,7 @@ import "net/url" // (Notes, Articles, etc) from unauthenticated (ie., logged-out) access via // web pages, web apps, web APIs, etc. This setting has no bearing on // dereferences via HTTP GET to ActivityPub endpoints (application/ld+json; -// profile="https://www.w3.org/ns/activitystreams"), for which GoToSocial -// always requires HTTP signatures. +// profile="https://www.w3.org/ns/activitystreams"). type GoToSocialHidesCcPublicFromUnauthedWebProperty interface { // Clear ensures no value of this property is set. Calling // IsXMLSchemaBoolean afterwards will return false. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesToPublicFromUnauthedWeb_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesToPublicFromUnauthedWeb_interface.go index f876e6eb2..e5ed0067e 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesToPublicFromUnauthedWeb_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_hidesToPublicFromUnauthedWeb_interface.go @@ -8,8 +8,7 @@ import "net/url" // (Notes, Articles, etc) from unauthenticated (ie., logged-out) access via // web pages, web apps, web APIs, etc. This setting has no bearing on // dereferences via HTTP GET to ActivityPub endpoints (application/ld+json; -// profile="https://www.w3.org/ns/activitystreams"), for which GoToSocial -// always requires HTTP signatures. +// profile="https://www.w3.org/ns/activitystreams"). type GoToSocialHidesToPublicFromUnauthedWebProperty interface { // Clear ensures no value of this property is set. Calling // IsXMLSchemaBoolean afterwards will return false. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_likeAuthorization_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_likeAuthorization_interface.go new file mode 100644 index 000000000..8c3ca0915 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_likeAuthorization_interface.go @@ -0,0 +1,52 @@ +// Code generated by astool. DO NOT EDIT. + +package vocab + +import "net/url" + +// URI/ID of a LikeAuthorization permitting the Like this property is attached to. +type GoToSocialLikeAuthorizationProperty interface { + // Clear ensures no value of this property is set. Calling + // IsXMLSchemaAnyURI afterwards will return false. + Clear() + // Get returns the value of this property. When IsXMLSchemaAnyURI returns + // false, Get will return any arbitrary value. + Get() *url.URL + // GetIRI returns the IRI of this property. When IsIRI returns false, + // GetIRI will return any arbitrary value. + GetIRI() *url.URL + // HasAny returns true if the value or IRI is set. + HasAny() bool + // IsIRI returns true if this property is an IRI. + IsIRI() bool + // IsXMLSchemaAnyURI returns true if this property is set and not an IRI. + IsXMLSchemaAnyURI() bool + // 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. + JSONLDContext() map[string]string + // 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. + KindIndex() int + // 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. + LessThan(o GoToSocialLikeAuthorizationProperty) bool + // Name returns the name of this property: "likeAuthorization". + Name() string + // 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. + Serialize() (interface{}, error) + // Set sets the value of this property. Calling IsXMLSchemaAnyURI + // afterwards will return true. + Set(v *url.URL) + // SetIRI sets the value of this property. Calling IsIRI afterwards will + // return true. + SetIRI(v *url.URL) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_replyAuthorization_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_replyAuthorization_interface.go new file mode 100644 index 000000000..078e5e3d0 --- /dev/null +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_property_gotosocial_replyAuthorization_interface.go @@ -0,0 +1,53 @@ +// Code generated by astool. DO NOT EDIT. + +package vocab + +import "net/url" + +// URI/ID of a ReplyAuthorization permitting the Object this property is attached +// to. +type GoToSocialReplyAuthorizationProperty interface { + // Clear ensures no value of this property is set. Calling + // IsXMLSchemaAnyURI afterwards will return false. + Clear() + // Get returns the value of this property. When IsXMLSchemaAnyURI returns + // false, Get will return any arbitrary value. + Get() *url.URL + // GetIRI returns the IRI of this property. When IsIRI returns false, + // GetIRI will return any arbitrary value. + GetIRI() *url.URL + // HasAny returns true if the value or IRI is set. + HasAny() bool + // IsIRI returns true if this property is an IRI. + IsIRI() bool + // IsXMLSchemaAnyURI returns true if this property is set and not an IRI. + IsXMLSchemaAnyURI() bool + // 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. + JSONLDContext() map[string]string + // 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. + KindIndex() int + // 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. + LessThan(o GoToSocialReplyAuthorizationProperty) bool + // Name returns the name of this property: "replyAuthorization". + Name() string + // 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. + Serialize() (interface{}, error) + // Set sets the value of this property. Calling IsXMLSchemaAnyURI + // afterwards will return true. + Set(v *url.URL) + // SetIRI sets the value of this property. Calling IsIRI afterwards will + // return true. + SetIRI(v *url.URL) +} diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_announce_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_announce_interface.go index 0b5aef0f1..5f8cf0eef 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_announce_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_announce_interface.go @@ -136,6 +136,9 @@ type ActivityStreamsAnnounce interface { // GetActivityStreamsUrl returns the "url" property if it exists, and nil // otherwise. GetActivityStreamsUrl() ActivityStreamsUrlProperty + // GetGoToSocialAnnounceAuthorization returns the "announceAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialAnnounceAuthorization() GoToSocialAnnounceAuthorizationProperty // GetGoToSocialApprovedBy returns the "approvedBy" property if it exists, // and nil otherwise. GetGoToSocialApprovedBy() GoToSocialApprovedByProperty @@ -241,6 +244,9 @@ type ActivityStreamsAnnounce interface { SetActivityStreamsUpdated(i ActivityStreamsUpdatedProperty) // SetActivityStreamsUrl sets the "url" property. SetActivityStreamsUrl(i ActivityStreamsUrlProperty) + // SetGoToSocialAnnounceAuthorization sets the "announceAuthorization" + // property. + SetGoToSocialAnnounceAuthorization(i GoToSocialAnnounceAuthorizationProperty) // SetGoToSocialApprovedBy sets the "approvedBy" property. SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetJSONLDId sets the "id" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_article_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_article_interface.go index 149fdb6a9..1dd2a5b51 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_article_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_article_interface.go @@ -118,6 +118,9 @@ type ActivityStreamsArticle interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -214,6 +217,8 @@ type ActivityStreamsArticle interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_audio_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_audio_interface.go index 70ad5d20a..032fd5473 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_audio_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_audio_interface.go @@ -118,6 +118,9 @@ type ActivityStreamsAudio interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -219,6 +222,8 @@ type ActivityStreamsAudio interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_document_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_document_interface.go index f417c9452..0a654bfe7 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_document_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_document_interface.go @@ -114,6 +114,9 @@ type ActivityStreamsDocument interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -216,6 +219,8 @@ type ActivityStreamsDocument interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_event_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_event_interface.go index 9edbb7b36..3a9e6546e 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_event_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_event_interface.go @@ -115,6 +115,9 @@ type ActivityStreamsEvent interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -210,6 +213,8 @@ type ActivityStreamsEvent interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_image_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_image_interface.go index 5073d044a..c7fb3b69d 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_image_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_image_interface.go @@ -131,6 +131,9 @@ type ActivityStreamsImage interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -236,6 +239,8 @@ type ActivityStreamsImage interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_like_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_like_interface.go index 1dcbdd914..f4501c23e 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_like_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_like_interface.go @@ -131,6 +131,9 @@ type ActivityStreamsLike interface { // GetGoToSocialApprovedBy returns the "approvedBy" property if it exists, // and nil otherwise. GetGoToSocialApprovedBy() GoToSocialApprovedByProperty + // GetGoToSocialLikeAuthorization returns the "likeAuthorization" property + // if it exists, and nil otherwise. + GetGoToSocialLikeAuthorization() GoToSocialLikeAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -234,6 +237,8 @@ type ActivityStreamsLike interface { SetActivityStreamsUrl(i ActivityStreamsUrlProperty) // SetGoToSocialApprovedBy sets the "approvedBy" property. SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) + // SetGoToSocialLikeAuthorization sets the "likeAuthorization" property. + SetGoToSocialLikeAuthorization(i GoToSocialLikeAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_note_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_note_interface.go index d78560050..4b1ecd095 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_note_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_note_interface.go @@ -115,6 +115,9 @@ type ActivityStreamsNote interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -210,6 +213,8 @@ type ActivityStreamsNote interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_page_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_page_interface.go index 635dab3b2..935069f03 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_page_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_page_interface.go @@ -114,6 +114,9 @@ type ActivityStreamsPage interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -215,6 +218,8 @@ type ActivityStreamsPage interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_place_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_place_interface.go index 0c983542e..bdd429a42 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_place_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_place_interface.go @@ -140,6 +140,9 @@ type ActivityStreamsPlace interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -245,6 +248,8 @@ type ActivityStreamsPlace interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_profile_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_profile_interface.go index b4b8a7697..65725835b 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_profile_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_profile_interface.go @@ -122,6 +122,9 @@ type ActivityStreamsProfile interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -220,6 +223,8 @@ type ActivityStreamsProfile interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_question_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_question_interface.go index c249bfc33..44cc24d71 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_question_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_question_interface.go @@ -157,6 +157,9 @@ type ActivityStreamsQuestion interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -270,6 +273,8 @@ type ActivityStreamsQuestion interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_video_interface.go b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_video_interface.go index c42dd635a..85c788605 100644 --- a/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_video_interface.go +++ b/vendor/code.superseriousbusiness.org/activity/streams/vocab/gen_type_activitystreams_video_interface.go @@ -115,6 +115,9 @@ type ActivityStreamsVideo interface { // GetGoToSocialInteractionPolicy returns the "interactionPolicy" property // if it exists, and nil otherwise. GetGoToSocialInteractionPolicy() GoToSocialInteractionPolicyProperty + // GetGoToSocialReplyAuthorization returns the "replyAuthorization" + // property if it exists, and nil otherwise. + GetGoToSocialReplyAuthorization() GoToSocialReplyAuthorizationProperty // GetJSONLDId returns the "id" property if it exists, and nil otherwise. GetJSONLDId() JSONLDIdProperty // GetJSONLDType returns the "type" property if it exists, and nil @@ -216,6 +219,8 @@ type ActivityStreamsVideo interface { SetGoToSocialApprovedBy(i GoToSocialApprovedByProperty) // SetGoToSocialInteractionPolicy sets the "interactionPolicy" property. SetGoToSocialInteractionPolicy(i GoToSocialInteractionPolicyProperty) + // SetGoToSocialReplyAuthorization sets the "replyAuthorization" property. + SetGoToSocialReplyAuthorization(i GoToSocialReplyAuthorizationProperty) // SetJSONLDId sets the "id" property. SetJSONLDId(i JSONLDIdProperty) // SetJSONLDType sets the "type" property. diff --git a/vendor/modules.txt b/vendor/modules.txt index 9034d1476..e2faccc3c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# code.superseriousbusiness.org/activity v1.16.0 +# code.superseriousbusiness.org/activity v1.17.0 ## explicit; go 1.23 code.superseriousbusiness.org/activity/pub code.superseriousbusiness.org/activity/streams @@ -139,6 +139,7 @@ code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_artist code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_library code.superseriousbusiness.org/activity/streams/impl/funkwhale/type_track code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_always +code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_announceauthorization code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvalrequired code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_approvedby code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_automaticapproval @@ -151,7 +152,9 @@ code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_hidestop code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactingobject code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactionpolicy code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_interactiontarget +code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_likeauthorization code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_manualapproval +code.superseriousbusiness.org/activity/streams/impl/gotosocial/property_replyauthorization code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceapproval code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announceauthorization code.superseriousbusiness.org/activity/streams/impl/gotosocial/type_announcerequest