mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	activitypub: implement /api/v1/activitypub/user/{username} (#14186)
Return informations regarding a Person (as defined in ActivityStreams https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person). Refs: https://github.com/go-gitea/gitea/issues/14186 Signed-off-by: Loïc Dachary <loic@dachary.org>
This commit is contained in:
		
				
					committed by
					
						 Anthony Wang
						Anthony Wang
					
				
			
			
				
	
			
			
			
						parent
						
							f2db473b0d
						
					
				
				
					commit
					4951af4d99
				
			
							
								
								
									
										63
									
								
								integrations/api_activitypub_person_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								integrations/api_activitypub_person_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| // Copyright 2021 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package integrations | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"github.com/go-fed/activity/streams" | ||||
| 	"github.com/go-fed/activity/streams/vocab" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestActivityPubPerson(t *testing.T) { | ||||
| 	onGiteaRun(t, func(*testing.T, *url.URL) { | ||||
| 		setting.Federation.Enabled = true | ||||
| 		defer func() { | ||||
| 			setting.Federation.Enabled = false | ||||
| 		}() | ||||
|  | ||||
| 		username := "user2" | ||||
| 		req := NewRequestf(t, "GET", fmt.Sprintf("/api/v1/activitypub/user/%s", username)) | ||||
| 		resp := MakeRequest(t, req, http.StatusOK) | ||||
| 		assert.Contains(t, string(resp.Body.Bytes()), "@context") | ||||
| 		var m map[string]interface{} | ||||
| 		_ = json.Unmarshal(resp.Body.Bytes(), &m) | ||||
|  | ||||
| 		var person vocab.ActivityStreamsPerson | ||||
| 		resolver, _ := streams.NewJSONResolver(func(c context.Context, p vocab.ActivityStreamsPerson) error { | ||||
| 			person = p | ||||
| 			return nil | ||||
| 		}) | ||||
| 		ctx := context.Background() | ||||
| 		err := resolver.Resolve(ctx, m) | ||||
| 		assert.Equal(t, err, nil) | ||||
| 		assert.Equal(t, person.GetTypeName(), "Person") | ||||
| 		assert.Equal(t, person.GetActivityStreamsName().Begin().GetXMLSchemaString(), username) | ||||
| 		assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), person.GetJSONLDId().GetIRI().String()) | ||||
| 		assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.GetActivityStreamsOutbox().GetIRI().String()) | ||||
| 		assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/inbox$", username), person.GetActivityStreamsInbox().GetIRI().String()) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestActivityPubMissingPerson(t *testing.T) { | ||||
| 	onGiteaRun(t, func(*testing.T, *url.URL) { | ||||
| 		setting.Federation.Enabled = true | ||||
| 		defer func() { | ||||
| 			setting.Federation.Enabled = false | ||||
| 		}() | ||||
|  | ||||
| 		req := NewRequestf(t, "GET", "/api/v1/activitypub/user/nonexistentuser") | ||||
| 		resp := MakeRequest(t, req, http.StatusNotFound) | ||||
| 		assert.Contains(t, string(resp.Body.Bytes()), "GetUserByName") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										9
									
								
								modules/structs/activitypub.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/structs/activitypub.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| // Copyright 2021 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package structs | ||||
|  | ||||
| type ActivityPub struct { | ||||
| 	Context string `json:"@context"` | ||||
| } | ||||
							
								
								
									
										62
									
								
								routers/api/v1/activitypub/person.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								routers/api/v1/activitypub/person.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Copyright 2021 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package activitypub | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/user" | ||||
| 	"github.com/go-fed/activity/streams" | ||||
| ) | ||||
|  | ||||
| func Person(ctx *context.APIContext) { | ||||
| 	// swagger:operation GET /activitypub/user/{username} information | ||||
| 	// --- | ||||
| 	// summary: Returns the person | ||||
| 	// produces: | ||||
| 	// - application/json | ||||
| 	// parameters: | ||||
| 	// - name: username | ||||
| 	//   in: path | ||||
| 	//   description: username of the user | ||||
| 	//   type: string | ||||
| 	//   required: true | ||||
| 	// responses: | ||||
| 	//   "200": | ||||
| 	//     "$ref": "#/responses/ActivityPub" | ||||
|  | ||||
| 	user.GetUserByParamsName(ctx, "username") | ||||
| 	username := ctx.Params("username") | ||||
|  | ||||
| 	person := streams.NewActivityStreamsPerson() | ||||
|  | ||||
| 	id := streams.NewJSONLDIdProperty() | ||||
| 	link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/") | ||||
| 	url_object, _ := url.Parse(link) | ||||
| 	id.SetIRI(url_object) | ||||
| 	person.SetJSONLDId(id) | ||||
|  | ||||
| 	name := streams.NewActivityStreamsNameProperty() | ||||
| 	name.AppendXMLSchemaString(username) | ||||
| 	person.SetActivityStreamsName(name) | ||||
|  | ||||
| 	ibox := streams.NewActivityStreamsInboxProperty() | ||||
| 	url_object, _ = url.Parse(link + "/inbox") | ||||
| 	ibox.SetIRI(url_object) | ||||
| 	person.SetActivityStreamsInbox(ibox) | ||||
|  | ||||
| 	obox := streams.NewActivityStreamsOutboxProperty() | ||||
| 	url_object, _ = url.Parse(link + "/outbox") | ||||
| 	obox.SetIRI(url_object) | ||||
| 	person.SetActivityStreamsOutbox(obox) | ||||
|  | ||||
| 	var jsonmap map[string]interface{} | ||||
| 	jsonmap, _ = streams.Serialize(person) | ||||
| 	ctx.JSON(http.StatusOK, jsonmap) | ||||
| } | ||||
| @@ -79,6 +79,7 @@ import ( | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 	"code.gitea.io/gitea/modules/web" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/activitypub" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/admin" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/misc" | ||||
| 	"code.gitea.io/gitea/routers/api/v1/notify" | ||||
| @@ -597,6 +598,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { | ||||
| 		m.Get("/version", misc.Version) | ||||
| 		if setting.Federation.Enabled { | ||||
| 			m.Get("/nodeinfo", misc.NodeInfo) | ||||
| 			m.Group("/activitypub", func() { | ||||
| 				m.Group("/user/{username}", func() { | ||||
| 					m.Get("", activitypub.Person) | ||||
| 				}) | ||||
| 			}) | ||||
| 		} | ||||
| 		m.Get("/signing-key.gpg", misc.SigningKey) | ||||
| 		m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) | ||||
|   | ||||
							
								
								
									
										16
									
								
								routers/api/v1/swagger/activitypub.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								routers/api/v1/swagger/activitypub.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // Copyright 2021 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package swagger | ||||
|  | ||||
| import ( | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| ) | ||||
|  | ||||
| // ActivityPub | ||||
| // swagger:response ActivityPub | ||||
| type swaggerResponseActivityPub struct { | ||||
| 	// in:body | ||||
| 	Body api.ActivityPub `json:"body"` | ||||
| } | ||||
| @@ -23,6 +23,29 @@ | ||||
|   }, | ||||
|   "basePath": "{{AppSubUrl | JSEscape | Safe}}/api/v1", | ||||
|   "paths": { | ||||
|     "/activitypub/user/{username}": { | ||||
|       "get": { | ||||
|         "produces": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "summary": "Returns the person", | ||||
|         "operationId": "information", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "username of the user", | ||||
|             "name": "username", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "$ref": "#/responses/ActivityPub" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/admin/cron": { | ||||
|       "get": { | ||||
|         "produces": [ | ||||
| @@ -12700,6 +12723,16 @@ | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "ActivityPub": { | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "@context": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Context" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "AddCollaboratorOption": { | ||||
|       "description": "AddCollaboratorOption options when adding a user as a collaborator of a repository", | ||||
|       "type": "object", | ||||
| @@ -18235,6 +18268,12 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "ActivityPub": { | ||||
|       "description": "ActivityPub", | ||||
|       "schema": { | ||||
|         "$ref": "#/definitions/ActivityPub" | ||||
|       } | ||||
|     }, | ||||
|     "AnnotatedTag": { | ||||
|       "description": "AnnotatedTag", | ||||
|       "schema": { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user