Add following and follower ActivityStreams endpoints

This commit is contained in:
Anthony Wang 2022-04-24 14:23:11 -05:00
parent fb9b8562f6
commit 838345815d
Signed by: a
GPG key ID: BC96B00AEC5F2D76
3 changed files with 172 additions and 9 deletions

View file

@ -11,11 +11,13 @@ import (
"net/url"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/api/v1/utils"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
@ -66,6 +68,16 @@ func Person(ctx *context.APIContext) {
obox.SetIRI(urlObject)
person.SetActivityStreamsOutbox(obox)
following := streams.NewActivityStreamsFollowingProperty()
urlObject, _ = url.Parse(link + "/following")
following.SetIRI(urlObject)
person.SetActivityStreamsFollowing(following)
followers := streams.NewActivityStreamsFollowersProperty()
urlObject, _ = url.Parse(link + "/followers")
followers.SetIRI(urlObject)
person.SetActivityStreamsFollowers(followers)
publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty()
publicKeyType := streams.NewW3IDSecurityV1PublicKey()
@ -104,7 +116,7 @@ func PersonInboxGet(ctx *context.APIContext) {
// ---
// summary: Returns the inbox
// produces:
// - application/json
// - application/activity+json
// parameters:
// - name: username
// in: path
@ -167,7 +179,7 @@ func PersonOutboxGet(ctx *context.APIContext) {
// ---
// summary: Returns the outbox
// produces:
// - application/json
// - application/activity+json
// parameters:
// - name: username
// in: path
@ -251,3 +263,98 @@ func PersonOutboxPost(ctx *context.APIContext) {
*/
ctx.Status(http.StatusNoContent)
}
// PersonFollowing function
func PersonFollowing(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/following activitypub activitypubPersonFollowing
// ---
// summary: Returns the following collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
user := user.GetUserByParamsName(ctx, "username")
if user == nil {
return
}
users, err := user_model.GetUserFollowing(user, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
return
}
following := streams.NewActivityStreamsOrderedCollection()
totalItems := streams.NewActivityStreamsTotalItemsProperty()
totalItems.Set(len(users))
following.SetActivityStreamsTotalItems(totalItems)
items := streams.NewActivityStreamsOrderedItemsProperty()
for i := 0; i < len(users); i++ {
user, _ := url.Parse(setting.AppURL+"api/v1/activitypub/user/"+users[i].Name)
items.AppendIRI(user)
}
following.SetActivityStreamsOrderedItems(items)
jsonmap, err := streams.Serialize(following)
if err != nil {
ctx.Error(http.StatusInternalServerError, "Serialize", err)
}
ctx.JSON(http.StatusOK, jsonmap)
}
// PersonFollowers function
func PersonFollowers(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/followers activitypub activitypubPersonFollowers
// ---
// summary: Returns the followers collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
user := user.GetUserByParamsName(ctx, "username")
if user == nil {
return
}
users, err := user_model.GetUserFollowers(user, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
return
}
followers := streams.NewActivityStreamsOrderedCollection()
totalItems := streams.NewActivityStreamsTotalItemsProperty()
totalItems.Set(len(users))
followers.SetActivityStreamsTotalItems(totalItems)
items := streams.NewActivityStreamsOrderedItemsProperty()
for i := 0; i < len(users); i++ {
user, _ := url.Parse(setting.AppURL+"api/v1/activitypub/user/"+users[i].Name)
items.AppendIRI(user)
}
followers.SetActivityStreamsOrderedItems(items)
jsonmap, err := streams.Serialize(followers)
fmt.Println(jsonmap)
if err != nil {
ctx.Error(http.StatusInternalServerError, "Serialize", err)
}
ctx.JSON(http.StatusOK, jsonmap)
}

View file

@ -599,11 +599,15 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
if setting.Federation.Enabled {
m.Get("/nodeinfo", misc.NodeInfo)
m.Group("/activitypub", func() {
m.Get("/user/{username}", activitypub.Person)
m.Get("/user/{username}/inbox", activitypub.PersonInboxGet)
m.Post("/user/{username}/inbox", activitypub.ReqSignature(), activitypub.PersonInboxPost)
m.Get("/user/{username}/outbox", activitypub.PersonOutboxGet)
m.Post("/user/{username}/outbox", activitypub.ReqSignature(), activitypub.PersonOutboxPost)
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
m.Get("/inbox", activitypub.PersonInboxGet)
m.Post("/inbox", activitypub.ReqSignature(), activitypub.PersonInboxPost)
m.Get("/outbox", activitypub.PersonOutboxGet)
m.Post("/outbox", activitypub.ReqSignature(), activitypub.PersonOutboxPost)
m.Get("/following", activitypub.PersonFollowing)
m.Get("/followers", activitypub.PersonFollowers)
})
})
}
m.Get("/signing-key.gpg", misc.SigningKey)

View file

@ -52,7 +52,7 @@
"/activitypub/user/{username}/inbox": {
"get": {
"produces": [
"application/json"
"application/activity+json"
],
"tags": [
"activitypub"
@ -102,7 +102,7 @@
"/activitypub/user/{username}/outbox": {
"get": {
"produces": [
"application/json"
"application/activity+json"
],
"tags": [
"activitypub"
@ -149,6 +149,58 @@
}
}
},
"/activitypub/user/{username}/following": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the following collection",
"operationId": "activitypubPersonFollowing",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/followers": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the followers collection",
"operationId": "activitypubPersonFollowers",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/admin/cron": {
"get": {
"produces": [