Close #5666 Add APIs for getting activity feeds.tags/v1.20.0-rc0
@@ -66,6 +66,67 @@ const ( | |||
ActionAutoMergePullRequest // 27 | |||
) | |||
func (at ActionType) String() string { | |||
switch at { | |||
case ActionCreateRepo: | |||
return "create_repo" | |||
case ActionRenameRepo: | |||
return "rename_repo" | |||
case ActionStarRepo: | |||
return "star_repo" | |||
case ActionWatchRepo: | |||
return "watch_repo" | |||
case ActionCommitRepo: | |||
return "commit_repo" | |||
case ActionCreateIssue: | |||
return "create_issue" | |||
case ActionCreatePullRequest: | |||
return "create_pull_request" | |||
case ActionTransferRepo: | |||
return "transfer_repo" | |||
case ActionPushTag: | |||
return "push_tag" | |||
case ActionCommentIssue: | |||
return "comment_issue" | |||
case ActionMergePullRequest: | |||
return "merge_pull_request" | |||
case ActionCloseIssue: | |||
return "close_issue" | |||
case ActionReopenIssue: | |||
return "reopen_issue" | |||
case ActionClosePullRequest: | |||
return "close_pull_request" | |||
case ActionReopenPullRequest: | |||
return "reopen_pull_request" | |||
case ActionDeleteTag: | |||
return "delete_tag" | |||
case ActionDeleteBranch: | |||
return "delete_branch" | |||
case ActionMirrorSyncPush: | |||
return "mirror_sync_push" | |||
case ActionMirrorSyncCreate: | |||
return "mirror_sync_create" | |||
case ActionMirrorSyncDelete: | |||
return "mirror_sync_delete" | |||
case ActionApprovePullRequest: | |||
return "approve_pull_request" | |||
case ActionRejectPullRequest: | |||
return "reject_pull_request" | |||
case ActionCommentPull: | |||
return "comment_pull" | |||
case ActionPublishRelease: | |||
return "publish_release" | |||
case ActionPullReviewDismissed: | |||
return "pull_review_dismissed" | |||
case ActionPullRequestReadyForReview: | |||
return "pull_request_ready_for_review" | |||
case ActionAutoMergePullRequest: | |||
return "auto_merge_pull_request" | |||
default: | |||
return "action-" + strconv.Itoa(int(at)) | |||
} | |||
} | |||
// Action represents user operation type and other information to | |||
// repository. It implemented interface base.Actioner so that can be | |||
// used in template render. |
@@ -0,0 +1,22 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package structs | |||
import "time" | |||
type Activity struct { | |||
ID int64 `json:"id"` | |||
UserID int64 `json:"user_id"` // Receiver user | |||
OpType string `json:"op_type"` | |||
ActUserID int64 `json:"act_user_id"` | |||
ActUser *User `json:"act_user"` | |||
RepoID int64 `json:"repo_id"` | |||
Repo *Repository `json:"repo"` | |||
CommentID int64 `json:"comment_id"` | |||
Comment *Comment `json:"comment"` | |||
RefName string `json:"ref_name"` | |||
IsPrivate bool `json:"is_private"` | |||
Content string `json:"content"` | |||
Created time.Time `json:"created"` | |||
} |
@@ -754,6 +754,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken) | |||
m.Combo("/{id}").Delete(user.DeleteAccessToken) | |||
}, reqBasicAuth()) | |||
m.Get("/activities/feeds", user.ListUserActivityFeeds) | |||
}, context_service.UserAssignmentAPI()) | |||
}) | |||
@@ -1177,6 +1179,7 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig) | |||
m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig) | |||
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages) | |||
m.Get("/activities/feeds", repo.ListRepoActivityFeeds) | |||
}, repoAssignment()) | |||
}) | |||
@@ -1234,6 +1237,7 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
Patch(bind(api.EditHookOption{}), org.EditHook). | |||
Delete(org.DeleteHook) | |||
}, reqToken(auth_model.AccessTokenScopeAdminOrgHook), reqOrgOwnership(), reqWebhooksEnabled()) | |||
m.Get("/activities/feeds", org.ListOrgActivityFeeds) | |||
}, orgAssignment(true)) | |||
m.Group("/teams/{teamid}", func() { | |||
m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeam). | |||
@@ -1253,6 +1257,7 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), org.RemoveTeamRepository). | |||
Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeamRepo) | |||
}) | |||
m.Get("/activities/feeds", org.ListTeamActivityFeeds) | |||
}, orgAssignment(false, true), reqToken(""), reqTeamMembership()) | |||
m.Group("/admin", func() { |
@@ -7,6 +7,7 @@ package org | |||
import ( | |||
"net/http" | |||
activities_model "code.gitea.io/gitea/models/activities" | |||
"code.gitea.io/gitea/models/db" | |||
"code.gitea.io/gitea/models/organization" | |||
"code.gitea.io/gitea/models/perm" | |||
@@ -370,3 +371,69 @@ func Delete(ctx *context.APIContext) { | |||
} | |||
ctx.Status(http.StatusNoContent) | |||
} | |||
func ListOrgActivityFeeds(ctx *context.APIContext) { | |||
// swagger:operation GET /orgs/{org}/activities/feeds organization orgListActivityFeeds | |||
// --- | |||
// summary: List an organization's activity feeds | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: org | |||
// in: path | |||
// description: name of the org | |||
// type: string | |||
// required: true | |||
// - name: date | |||
// in: query | |||
// description: the date of the activities to be found | |||
// type: string | |||
// format: date | |||
// - name: page | |||
// in: query | |||
// description: page number of results to return (1-based) | |||
// type: integer | |||
// - name: limit | |||
// in: query | |||
// description: page size of results | |||
// type: integer | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/ActivityFeedsList" | |||
// "404": | |||
// "$ref": "#/responses/notFound" | |||
includePrivate := false | |||
if ctx.IsSigned { | |||
if ctx.Doer.IsAdmin { | |||
includePrivate = true | |||
} else { | |||
org := organization.OrgFromUser(ctx.ContextUser) | |||
isMember, err := org.IsOrgMember(ctx.Doer.ID) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) | |||
return | |||
} | |||
includePrivate = isMember | |||
} | |||
} | |||
listOptions := utils.GetListOptions(ctx) | |||
opts := activities_model.GetFeedsOptions{ | |||
RequestedUser: ctx.ContextUser, | |||
Actor: ctx.Doer, | |||
IncludePrivate: includePrivate, | |||
Date: ctx.FormString("date"), | |||
ListOptions: listOptions, | |||
} | |||
feeds, count, err := activities_model.GetFeeds(ctx, opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) | |||
} |
@@ -9,6 +9,7 @@ import ( | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
activities_model "code.gitea.io/gitea/models/activities" | |||
"code.gitea.io/gitea/models/organization" | |||
"code.gitea.io/gitea/models/perm" | |||
access_model "code.gitea.io/gitea/models/perm/access" | |||
@@ -792,3 +793,55 @@ func SearchTeam(ctx *context.APIContext) { | |||
"data": apiTeams, | |||
}) | |||
} | |||
func ListTeamActivityFeeds(ctx *context.APIContext) { | |||
// swagger:operation GET /teams/{id}/activities/feeds organization orgListTeamActivityFeeds | |||
// --- | |||
// summary: List a team's activity feeds | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: id | |||
// in: path | |||
// description: id of the team | |||
// type: integer | |||
// format: int64 | |||
// required: true | |||
// - name: date | |||
// in: query | |||
// description: the date of the activities to be found | |||
// type: string | |||
// format: date | |||
// - name: page | |||
// in: query | |||
// description: page number of results to return (1-based) | |||
// type: integer | |||
// - name: limit | |||
// in: query | |||
// description: page size of results | |||
// type: integer | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/ActivityFeedsList" | |||
// "404": | |||
// "$ref": "#/responses/notFound" | |||
listOptions := utils.GetListOptions(ctx) | |||
opts := activities_model.GetFeedsOptions{ | |||
RequestedTeam: ctx.Org.Team, | |||
Actor: ctx.Doer, | |||
IncludePrivate: true, | |||
Date: ctx.FormString("date"), | |||
ListOptions: listOptions, | |||
} | |||
feeds, count, err := activities_model.GetFeeds(ctx, opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) | |||
} |
@@ -10,6 +10,7 @@ import ( | |||
"strings" | |||
"time" | |||
activities_model "code.gitea.io/gitea/models/activities" | |||
"code.gitea.io/gitea/models/db" | |||
"code.gitea.io/gitea/models/organization" | |||
"code.gitea.io/gitea/models/perm" | |||
@@ -1199,3 +1200,59 @@ func ValidateIssueConfig(ctx *context.APIContext) { | |||
ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: false, Message: err.Error()}) | |||
} | |||
} | |||
func ListRepoActivityFeeds(ctx *context.APIContext) { | |||
// swagger:operation GET /repos/{owner}/{repo}/activities/feeds repository repoListActivityFeeds | |||
// --- | |||
// summary: List a repository's activity feeds | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: owner | |||
// in: path | |||
// description: owner of the repo | |||
// type: string | |||
// required: true | |||
// - name: repo | |||
// in: path | |||
// description: name of the repo | |||
// type: string | |||
// required: true | |||
// - name: date | |||
// in: query | |||
// description: the date of the activities to be found | |||
// type: string | |||
// format: date | |||
// - name: page | |||
// in: query | |||
// description: page number of results to return (1-based) | |||
// type: integer | |||
// - name: limit | |||
// in: query | |||
// description: page size of results | |||
// type: integer | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/ActivityFeedsList" | |||
// "404": | |||
// "$ref": "#/responses/notFound" | |||
listOptions := utils.GetListOptions(ctx) | |||
opts := activities_model.GetFeedsOptions{ | |||
RequestedRepo: ctx.Repo.Repository, | |||
Actor: ctx.Doer, | |||
IncludePrivate: true, | |||
Date: ctx.FormString("date"), | |||
ListOptions: listOptions, | |||
} | |||
feeds, count, err := activities_model.GetFeeds(ctx, opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) | |||
} |
@@ -0,0 +1,15 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package swagger | |||
import ( | |||
api "code.gitea.io/gitea/modules/structs" | |||
) | |||
// ActivityFeedsList | |||
// swagger:response ActivityFeedsList | |||
type swaggerActivityFeedsList struct { | |||
// in:body | |||
Body []api.Activity `json:"body"` | |||
} |
@@ -145,3 +145,60 @@ func GetUserHeatmapData(ctx *context.APIContext) { | |||
} | |||
ctx.JSON(http.StatusOK, heatmap) | |||
} | |||
func ListUserActivityFeeds(ctx *context.APIContext) { | |||
// swagger:operation GET /users/{username}/activities/feeds user userListActivityFeeds | |||
// --- | |||
// summary: List a user's activity feeds | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: username | |||
// in: path | |||
// description: username of user | |||
// type: string | |||
// required: true | |||
// - name: only-performed-by | |||
// in: query | |||
// description: if true, only show actions performed by the requested user | |||
// type: boolean | |||
// - name: date | |||
// in: query | |||
// description: the date of the activities to be found | |||
// type: string | |||
// format: date | |||
// - name: page | |||
// in: query | |||
// description: page number of results to return (1-based) | |||
// type: integer | |||
// - name: limit | |||
// in: query | |||
// description: page size of results | |||
// type: integer | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/ActivityFeedsList" | |||
// "404": | |||
// "$ref": "#/responses/notFound" | |||
includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) | |||
listOptions := utils.GetListOptions(ctx) | |||
opts := activities_model.GetFeedsOptions{ | |||
RequestedUser: ctx.ContextUser, | |||
Actor: ctx.Doer, | |||
IncludePrivate: includePrivate, | |||
OnlyPerformedBy: ctx.FormBool("only-performed-by"), | |||
Date: ctx.FormString("date"), | |||
ListOptions: listOptions, | |||
} | |||
feeds, count, err := activities_model.GetFeeds(ctx, opts) | |||
if err != nil { | |||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err) | |||
return | |||
} | |||
ctx.SetTotalCountHeader(count) | |||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) | |||
} |
@@ -0,0 +1,52 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package convert | |||
import ( | |||
"context" | |||
activities_model "code.gitea.io/gitea/models/activities" | |||
perm_model "code.gitea.io/gitea/models/perm" | |||
access_model "code.gitea.io/gitea/models/perm/access" | |||
user_model "code.gitea.io/gitea/models/user" | |||
"code.gitea.io/gitea/modules/log" | |||
api "code.gitea.io/gitea/modules/structs" | |||
) | |||
func ToActivity(ctx context.Context, ac *activities_model.Action, doer *user_model.User) *api.Activity { | |||
p, err := access_model.GetUserRepoPermission(ctx, ac.Repo, doer) | |||
if err != nil { | |||
log.Error("GetUserRepoPermission[%d]: %v", ac.RepoID, err) | |||
p.AccessMode = perm_model.AccessModeNone | |||
} | |||
result := &api.Activity{ | |||
ID: ac.ID, | |||
UserID: ac.UserID, | |||
OpType: ac.OpType.String(), | |||
ActUserID: ac.ActUserID, | |||
ActUser: ToUser(ctx, ac.ActUser, doer), | |||
RepoID: ac.RepoID, | |||
Repo: ToRepo(ctx, ac.Repo, p.AccessMode), | |||
RefName: ac.RefName, | |||
IsPrivate: ac.IsPrivate, | |||
Content: ac.Content, | |||
Created: ac.CreatedUnix.AsTime(), | |||
} | |||
if ac.Comment != nil { | |||
result.CommentID = ac.CommentID | |||
result.Comment = ToComment(ctx, ac.Comment) | |||
} | |||
return result | |||
} | |||
func ToActivities(ctx context.Context, al activities_model.ActionList, doer *user_model.User) []*api.Activity { | |||
result := make([]*api.Activity, 0, len(al)) | |||
for _, ac := range al { | |||
result = append(result, ToActivity(ctx, ac, doer)) | |||
} | |||
return result | |||
} |
@@ -1411,6 +1411,54 @@ | |||
} | |||
} | |||
}, | |||
"/orgs/{org}/activities/feeds": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"organization" | |||
], | |||
"summary": "List an organization's activity feeds", | |||
"operationId": "orgListActivityFeeds", | |||
"parameters": [ | |||
{ | |||
"type": "string", | |||
"description": "name of the org", | |||
"name": "org", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "string", | |||
"format": "date", | |||
"description": "the date of the activities to be found", | |||
"name": "date", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page number of results to return (1-based)", | |||
"name": "page", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page size of results", | |||
"name": "limit", | |||
"in": "query" | |||
} | |||
], | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/ActivityFeedsList" | |||
}, | |||
"404": { | |||
"$ref": "#/responses/notFound" | |||
} | |||
} | |||
} | |||
}, | |||
"/orgs/{org}/hooks": { | |||
"get": { | |||
"produces": [ | |||
@@ -2854,6 +2902,61 @@ | |||
} | |||
} | |||
}, | |||
"/repos/{owner}/{repo}/activities/feeds": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"repository" | |||
], | |||
"summary": "List a repository's activity feeds", | |||
"operationId": "repoListActivityFeeds", | |||
"parameters": [ | |||
{ | |||
"type": "string", | |||
"description": "owner of the repo", | |||
"name": "owner", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "string", | |||
"description": "name of the repo", | |||
"name": "repo", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "string", | |||
"format": "date", | |||
"description": "the date of the activities to be found", | |||
"name": "date", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page number of results to return (1-based)", | |||
"name": "page", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page size of results", | |||
"name": "limit", | |||
"in": "query" | |||
} | |||
], | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/ActivityFeedsList" | |||
}, | |||
"404": { | |||
"$ref": "#/responses/notFound" | |||
} | |||
} | |||
} | |||
}, | |||
"/repos/{owner}/{repo}/archive/{archive}": { | |||
"get": { | |||
"produces": [ | |||
@@ -12645,6 +12748,55 @@ | |||
} | |||
} | |||
}, | |||
"/teams/{id}/activities/feeds": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"organization" | |||
], | |||
"summary": "List a team's activity feeds", | |||
"operationId": "orgListTeamActivityFeeds", | |||
"parameters": [ | |||
{ | |||
"type": "integer", | |||
"format": "int64", | |||
"description": "id of the team", | |||
"name": "id", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "string", | |||
"format": "date", | |||
"description": "the date of the activities to be found", | |||
"name": "date", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page number of results to return (1-based)", | |||
"name": "page", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page size of results", | |||
"name": "limit", | |||
"in": "query" | |||
} | |||
], | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/ActivityFeedsList" | |||
}, | |||
"404": { | |||
"$ref": "#/responses/notFound" | |||
} | |||
} | |||
} | |||
}, | |||
"/teams/{id}/members": { | |||
"get": { | |||
"produces": [ | |||
@@ -14304,6 +14456,60 @@ | |||
} | |||
} | |||
}, | |||
"/users/{username}/activities/feeds": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"user" | |||
], | |||
"summary": "List a user's activity feeds", | |||
"operationId": "userListActivityFeeds", | |||
"parameters": [ | |||
{ | |||
"type": "string", | |||
"description": "username of user", | |||
"name": "username", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "boolean", | |||
"description": "if true, only show actions performed by the requested user", | |||
"name": "only-performed-by", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "string", | |||
"format": "date", | |||
"description": "the date of the activities to be found", | |||
"name": "date", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page number of results to return (1-based)", | |||
"name": "page", | |||
"in": "query" | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "page size of results", | |||
"name": "limit", | |||
"in": "query" | |||
} | |||
], | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/ActivityFeedsList" | |||
}, | |||
"404": { | |||
"$ref": "#/responses/notFound" | |||
} | |||
} | |||
} | |||
}, | |||
"/users/{username}/followers": { | |||
"get": { | |||
"produces": [ | |||
@@ -14894,6 +15100,67 @@ | |||
}, | |||
"x-go-package": "code.gitea.io/gitea/modules/structs" | |||
}, | |||
"Activity": { | |||
"type": "object", | |||
"properties": { | |||
"act_user": { | |||
"$ref": "#/definitions/User" | |||
}, | |||
"act_user_id": { | |||
"type": "integer", | |||
"format": "int64", | |||
"x-go-name": "ActUserID" | |||
}, | |||
"comment": { | |||
"$ref": "#/definitions/Comment" | |||
}, | |||
"comment_id": { | |||
"type": "integer", | |||
"format": "int64", | |||
"x-go-name": "CommentID" | |||
}, | |||
"content": { | |||
"type": "string", | |||
"x-go-name": "Content" | |||
}, | |||
"created": { | |||
"type": "string", | |||
"format": "date-time", | |||
"x-go-name": "Created" | |||
}, | |||
"id": { | |||
"type": "integer", | |||
"format": "int64", | |||
"x-go-name": "ID" | |||
}, | |||
"is_private": { | |||
"type": "boolean", | |||
"x-go-name": "IsPrivate" | |||
}, | |||
"op_type": { | |||
"type": "string", | |||
"x-go-name": "OpType" | |||
}, | |||
"ref_name": { | |||
"type": "string", | |||
"x-go-name": "RefName" | |||
}, | |||
"repo": { | |||
"$ref": "#/definitions/Repository" | |||
}, | |||
"repo_id": { | |||
"type": "integer", | |||
"format": "int64", | |||
"x-go-name": "RepoID" | |||
}, | |||
"user_id": { | |||
"type": "integer", | |||
"format": "int64", | |||
"x-go-name": "UserID" | |||
} | |||
}, | |||
"x-go-package": "code.gitea.io/gitea/modules/structs" | |||
}, | |||
"ActivityPub": { | |||
"description": "ActivityPub type", | |||
"type": "object", | |||
@@ -20942,6 +21209,15 @@ | |||
} | |||
} | |||
}, | |||
"ActivityFeedsList": { | |||
"description": "ActivityFeedsList", | |||
"schema": { | |||
"type": "array", | |||
"items": { | |||
"$ref": "#/definitions/Activity" | |||
} | |||
} | |||
}, | |||
"ActivityPub": { | |||
"description": "ActivityPub", | |||
"schema": { |