summaryrefslogtreecommitdiff
path: root/internal/ap
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2025-02-19 18:09:54 +0100
committerLibravatar GitHub <noreply@github.com>2025-02-19 18:09:54 +0100
commit96716e4f43341beb3431a7caad10d48e6ca844ae (patch)
tree49e0771a80c5ecdf2cfc42969036fa6044382209 /internal/ap
parentadds more code comments and some small code formatting tweaks (#3799) (diff)
downloadgotosocial-96716e4f43341beb3431a7caad10d48e6ca844ae.tar.xz
[feature] Forward-compatibility with Approval objects (#3807)
* vendor * [feature] Forward-compatibility with Approval objects * vendor the thing * fix leetle bug * lil syntax tweak for beloved kimb
Diffstat (limited to 'internal/ap')
-rw-r--r--internal/ap/activitystreams.go5
-rw-r--r--internal/ap/interfaces.go50
-rw-r--r--internal/ap/resolve.go58
3 files changed, 70 insertions, 43 deletions
diff --git a/internal/ap/activitystreams.go b/internal/ap/activitystreams.go
index 50955ce2c..3851d0efb 100644
--- a/internal/ap/activitystreams.go
+++ b/internal/ap/activitystreams.go
@@ -97,6 +97,11 @@ const (
// Not in the AS spec, just used internally to indicate
// that we don't *yet* know what type of Object something is.
ObjectUnknown = "Unknown"
+
+ // Extensions and unofficial additions.
+ ObjectLikeApproval = "LikeApproval"
+ ObjectReplyApproval = "ReplyApproval"
+ ObjectAnnounceApproval = "AnnounceApproval"
)
// isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity).
diff --git a/internal/ap/interfaces.go b/internal/ap/interfaces.go
index fdd5e4a0b..acc799640 100644
--- a/internal/ap/interfaces.go
+++ b/internal/ap/interfaces.go
@@ -128,16 +128,13 @@ func ToPollOptionable(t vocab.Type) (PollOptionable, bool) {
}
// IsAccept returns whether AS vocab type name
-// is something that can be cast to Accept.
+// is something that can be cast to Acceptable.
func IsAcceptable(typeName string) bool {
return typeName == ActivityAccept
}
-// ToAcceptable safely tries to cast vocab.Type as vocab.ActivityStreamsAccept.
-//
-// TODO: Add additional "Accept" types here, eg., "ApproveReply" from
-// https://codeberg.org/fediverse/fep/src/branch/main/fep/5624/fep-5624.md
-func ToAcceptable(t vocab.Type) (vocab.ActivityStreamsAccept, bool) {
+// ToAcceptable safely tries to cast vocab.Type as Acceptable.
+func ToAcceptable(t vocab.Type) (Acceptable, bool) {
acceptable, ok := t.(vocab.ActivityStreamsAccept)
if !ok || !IsAcceptable(t.GetTypeName()) {
return nil, false
@@ -145,6 +142,28 @@ func ToAcceptable(t vocab.Type) (vocab.ActivityStreamsAccept, bool) {
return acceptable, true
}
+// IsApprovable returns whether AS vocab type name
+// is something that can be cast to Approvable.
+func IsApprovable(typeName string) bool {
+ switch typeName {
+ case ObjectLikeApproval,
+ ObjectReplyApproval,
+ ObjectAnnounceApproval:
+ return true
+ default:
+ return false
+ }
+}
+
+// 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()) {
+ return nil, false
+ }
+ return approvable, 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).
@@ -247,6 +266,19 @@ type PollOptionable interface {
// interface for representing an Accept.
type Acceptable interface {
Activityable
+
+ WithTarget
+ WithResult
+}
+
+// Approvable represents the minimum activitypub interface
+// for a LikeApproval, ReplyApproval, or AnnounceApproval.
+type Approvable interface {
+ vocab.Type
+
+ WithAttributedTo
+ WithObject
+ WithTarget
}
// Attachmentable represents the minimum activitypub interface for representing a 'mediaAttachment'. (see: IsAttachmentable).
@@ -708,3 +740,9 @@ type WithApprovedBy interface {
GetGoToSocialApprovedBy() vocab.GoToSocialApprovedByProperty
SetGoToSocialApprovedBy(vocab.GoToSocialApprovedByProperty)
}
+
+// WithVotersCount represents an activity or object the result property.
+type WithResult interface {
+ GetActivityStreamsResult() vocab.ActivityStreamsResultProperty
+ SetActivityStreamsResult(vocab.ActivityStreamsResultProperty)
+}
diff --git a/internal/ap/resolve.go b/internal/ap/resolve.go
index 76a8809c3..82a242710 100644
--- a/internal/ap/resolve.go
+++ b/internal/ap/resolve.go
@@ -198,48 +198,12 @@ func ResolveCollectionPage(ctx context.Context, body io.ReadCloser) (CollectionP
return ToCollectionPageIterator(t)
}
-// ResolveAcceptable tries to resolve the given reader
-// into an ActivityStreams Acceptable representation.
-func ResolveAcceptable(
- ctx context.Context,
- body io.ReadCloser,
-) (Acceptable, error) {
- // Get "raw" map
- // destination.
- raw := getMap()
- // Release.
- defer putMap(raw)
-
- // Decode data as JSON into 'raw' map
- // and get the resolved AS vocab.Type.
- // (this handles close of given body).
- t, err := decodeType(ctx, body, raw)
- if err != nil {
- return nil, gtserror.SetWrongType(err)
- }
-
- // Attempt to cast as acceptable.
- acceptable, ok := ToAcceptable(t)
- if !ok {
- err := gtserror.Newf("cannot resolve vocab type %T as acceptable", t)
- return nil, gtserror.SetWrongType(err)
- }
-
- return acceptable, nil
-}
-
// emptydest is an empty JSON decode
// destination useful for "noop" decodes
// to check underlying reader is empty.
var emptydest = &struct{}{}
-// decodeType tries to read and parse the data
-// at provided io.ReadCloser as a JSON ActivityPub
-// type, failing if not parseable as JSON or not
-// resolveable as one of our known AS types.
-//
-// NOTE: this function handles closing
-// given body when it is finished with.
+// decodeType is the package-internal version of DecodeType.
//
// The given map pointer will also be populated with
// the 'raw' JSON data, for further processing.
@@ -284,3 +248,23 @@ func decodeType(
return t, nil
}
+
+// DecodeType tries to read and parse the data
+// at provided io.ReadCloser as a JSON ActivityPub
+// type, failing if not parseable as JSON or not
+// resolveable as one of our known AS types.
+//
+// NOTE: this function handles closing
+// given body when it is finished with.
+func DecodeType(
+ ctx context.Context,
+ body io.ReadCloser,
+) (vocab.Type, error) {
+ // Get "raw" map
+ // destination.
+ raw := getMap()
+ // Release.
+ defer putMap(raw)
+
+ return decodeType(ctx, body, raw)
+}