This adds a API for getting License templates. This tries to be as close to the [GitHub API](https://docs.github.com/en/rest/licenses?apiVersion=2022-11-28) as possible, but Gitea does not support all features that GitHub has. I think they should been added, but this out f the scope of this PR. You should merge #23006 before this PR for security reasons.tags/v1.20.0-rc0
@@ -72,6 +72,22 @@ type ServerVersion struct { | |||
Version string `json:"version"` | |||
} | |||
// LicensesListEntry is used for the API | |||
type LicensesTemplateListEntry struct { | |||
Key string `json:"key"` | |||
Name string `json:"name"` | |||
URL string `json:"url"` | |||
} | |||
// LicensesInfo contains information about a License | |||
type LicenseTemplateInfo struct { | |||
Key string `json:"key"` | |||
Name string `json:"name"` | |||
URL string `json:"url"` | |||
Implementation string `json:"implementation"` | |||
Body string `json:"body"` | |||
} | |||
// APIError is an api error with a message | |||
type APIError struct { | |||
Message string `json:"message"` |
@@ -719,6 +719,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
m.Post("/markup", bind(api.MarkupOption{}), misc.Markup) | |||
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) | |||
m.Post("/markdown/raw", misc.MarkdownRaw) | |||
m.Get("/licenses", misc.ListLicenseTemplates) | |||
m.Get("/licenses/{name}", misc.GetLicenseTemplateInfo) | |||
m.Group("/settings", func() { | |||
m.Get("/ui", settings.GetGeneralUISettings) | |||
m.Get("/api", settings.GetGeneralAPISettings) |
@@ -0,0 +1,76 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package misc | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"net/url" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/options" | |||
repo_module "code.gitea.io/gitea/modules/repository" | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
) | |||
// Returns a list of all License templates | |||
func ListLicenseTemplates(ctx *context.APIContext) { | |||
// swagger:operation GET /licenses miscellaneous listLicenseTemplates | |||
// --- | |||
// summary: Returns a list of all license templates | |||
// produces: | |||
// - application/json | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/LicenseTemplateList" | |||
response := make([]api.LicensesTemplateListEntry, len(repo_module.Licenses)) | |||
for i, license := range repo_module.Licenses { | |||
response[i] = api.LicensesTemplateListEntry{ | |||
Key: license, | |||
Name: license, | |||
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(license)), | |||
} | |||
} | |||
ctx.JSON(http.StatusOK, response) | |||
} | |||
// Returns information about a gitignore template | |||
func GetLicenseTemplateInfo(ctx *context.APIContext) { | |||
// swagger:operation GET /licenses/{name} miscellaneous getLicenseTemplateInfo | |||
// --- | |||
// summary: Returns information about a license template | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: name | |||
// in: path | |||
// description: name of the license | |||
// type: string | |||
// required: true | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/LicenseTemplateInfo" | |||
// "404": | |||
// "$ref": "#/responses/notFound" | |||
name := util.PathJoinRelX(ctx.Params("name")) | |||
text, err := options.License(name) | |||
if err != nil { | |||
ctx.NotFound() | |||
return | |||
} | |||
response := api.LicenseTemplateInfo{ | |||
Key: name, | |||
Name: name, | |||
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(name)), | |||
Body: string(text), | |||
// This is for combatibilty with the GitHub API. This Text is for some reason added to each License response. | |||
Implementation: "Create a text file (typically named LICENSE or LICENSE.txt) in the root of your source code and copy the text of the license into the file", | |||
} | |||
ctx.JSON(http.StatusOK, response) | |||
} |
@@ -14,6 +14,20 @@ type swaggerResponseServerVersion struct { | |||
Body api.ServerVersion `json:"body"` | |||
} | |||
// LicenseTemplateList | |||
// swagger:response LicenseTemplateList | |||
type swaggerResponseLicensesTemplateList struct { | |||
// in:body | |||
Body []api.LicensesTemplateListEntry `json:"body"` | |||
} | |||
// LicenseTemplateInfo | |||
// swagger:response LicenseTemplateInfo | |||
type swaggerResponseLicenseTemplateInfo struct { | |||
// in:body | |||
Body api.LicenseTemplateInfo `json:"body"` | |||
} | |||
// StringSlice | |||
// swagger:response StringSlice | |||
type swaggerResponseStringSlice struct { |
@@ -883,6 +883,52 @@ | |||
} | |||
} | |||
}, | |||
"/licenses": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"miscellaneous" | |||
], | |||
"summary": "Returns a list of all license templates", | |||
"operationId": "listLicenseTemplates", | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/LicenseTemplateList" | |||
} | |||
} | |||
} | |||
}, | |||
"/licenses/{name}": { | |||
"get": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"miscellaneous" | |||
], | |||
"summary": "Returns information about a license template", | |||
"operationId": "getLicenseTemplateInfo", | |||
"parameters": [ | |||
{ | |||
"type": "string", | |||
"description": "name of the license", | |||
"name": "name", | |||
"in": "path", | |||
"required": true | |||
} | |||
], | |||
"responses": { | |||
"200": { | |||
"$ref": "#/responses/LicenseTemplateInfo" | |||
}, | |||
"404": { | |||
"$ref": "#/responses/notFound" | |||
} | |||
} | |||
} | |||
}, | |||
"/markdown": { | |||
"post": { | |||
"consumes": [ | |||
@@ -18704,6 +18750,52 @@ | |||
}, | |||
"x-go-package": "code.gitea.io/gitea/modules/structs" | |||
}, | |||
"LicenseTemplateInfo": { | |||
"description": "LicensesInfo contains information about a License", | |||
"type": "object", | |||
"properties": { | |||
"body": { | |||
"type": "string", | |||
"x-go-name": "Body" | |||
}, | |||
"implementation": { | |||
"type": "string", | |||
"x-go-name": "Implementation" | |||
}, | |||
"key": { | |||
"type": "string", | |||
"x-go-name": "Key" | |||
}, | |||
"name": { | |||
"type": "string", | |||
"x-go-name": "Name" | |||
}, | |||
"url": { | |||
"type": "string", | |||
"x-go-name": "URL" | |||
} | |||
}, | |||
"x-go-package": "code.gitea.io/gitea/modules/structs" | |||
}, | |||
"LicensesTemplateListEntry": { | |||
"description": "LicensesListEntry is used for the API", | |||
"type": "object", | |||
"properties": { | |||
"key": { | |||
"type": "string", | |||
"x-go-name": "Key" | |||
}, | |||
"name": { | |||
"type": "string", | |||
"x-go-name": "Name" | |||
}, | |||
"url": { | |||
"type": "string", | |||
"x-go-name": "URL" | |||
} | |||
}, | |||
"x-go-package": "code.gitea.io/gitea/modules/structs" | |||
}, | |||
"MarkdownOption": { | |||
"description": "MarkdownOption markdown options", | |||
"type": "object", | |||
@@ -21587,6 +21679,21 @@ | |||
} | |||
} | |||
}, | |||
"LicenseTemplateInfo": { | |||
"description": "LicenseTemplateInfo", | |||
"schema": { | |||
"$ref": "#/definitions/LicenseTemplateInfo" | |||
} | |||
}, | |||
"LicenseTemplateList": { | |||
"description": "LicenseTemplateList", | |||
"schema": { | |||
"type": "array", | |||
"items": { | |||
"$ref": "#/definitions/LicensesTemplateListEntry" | |||
} | |||
} | |||
}, | |||
"MarkdownRender": { | |||
"description": "MarkdownRender is a rendered markdown document", | |||
"schema": { |
@@ -0,0 +1,55 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package integration | |||
import ( | |||
"fmt" | |||
"net/http" | |||
"net/url" | |||
"testing" | |||
"code.gitea.io/gitea/modules/options" | |||
repo_module "code.gitea.io/gitea/modules/repository" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/tests" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestAPIListLicenseTemplates(t *testing.T) { | |||
defer tests.PrepareTestEnv(t)() | |||
req := NewRequest(t, "GET", "/api/v1/licenses") | |||
resp := MakeRequest(t, req, http.StatusOK) | |||
// This tests if the API returns a list of strings | |||
var licenseList []api.LicensesTemplateListEntry | |||
DecodeJSON(t, resp, &licenseList) | |||
} | |||
func TestAPIGetLicenseTemplateInfo(t *testing.T) { | |||
defer tests.PrepareTestEnv(t)() | |||
// If Gitea has for some reason no License templates, we need to skip this test | |||
if len(repo_module.Licenses) == 0 { | |||
return | |||
} | |||
// Use the first template for the test | |||
licenseName := repo_module.Licenses[0] | |||
urlStr := fmt.Sprintf("/api/v1/licenses/%s", url.PathEscape(licenseName)) | |||
req := NewRequest(t, "GET", urlStr) | |||
resp := MakeRequest(t, req, http.StatusOK) | |||
var licenseInfo api.LicenseTemplateInfo | |||
DecodeJSON(t, resp, &licenseInfo) | |||
// We get the text of the template here | |||
text, _ := options.License(licenseName) | |||
assert.Equal(t, licenseInfo.Key, licenseName) | |||
assert.Equal(t, licenseInfo.Name, licenseName) | |||
assert.Equal(t, licenseInfo.Body, string(text)) | |||
} |