feat: implement organization secret creation API (#26566)
- Add a new `CreateSecretOption` struct for creating secrets - Implement a `CreateOrgSecret` function to create a secret in an organization - Add a new route in `api.go` to handle the creation of organization secrets - Update the Swagger template to include the new `CreateOrgSecret` API endpoint --------- Signed-off-by: appleboy <appleboy.tw@gmail.com>
This commit is contained in:
parent
a4a567f29f
commit
23addde28e
|
@ -5,7 +5,7 @@ package structs
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// User represents a secret
|
// Secret represents a secret
|
||||||
// swagger:model
|
// swagger:model
|
||||||
type Secret struct {
|
type Secret struct {
|
||||||
// the secret's name
|
// the secret's name
|
||||||
|
@ -13,3 +13,15 @@ type Secret struct {
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Created time.Time `json:"created_at"`
|
Created time.Time `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateSecretOption options when creating secret
|
||||||
|
// swagger:model
|
||||||
|
type CreateSecretOption struct {
|
||||||
|
// Name of the secret to create
|
||||||
|
//
|
||||||
|
// required: true
|
||||||
|
// unique: true
|
||||||
|
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||||
|
// Data of the secret to create
|
||||||
|
Data string `json:"data" binding:"Required"`
|
||||||
|
}
|
||||||
|
|
|
@ -1300,6 +1300,7 @@ func Routes() *web.Route {
|
||||||
})
|
})
|
||||||
m.Group("/actions/secrets", func() {
|
m.Group("/actions/secrets", func() {
|
||||||
m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
|
m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
|
||||||
|
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateSecretOption{}), org.CreateOrgSecret)
|
||||||
})
|
})
|
||||||
m.Group("/public_members", func() {
|
m.Group("/public_members", func() {
|
||||||
m.Get("", org.ListPublicMembers)
|
m.Get("", org.ListPublicMembers)
|
||||||
|
|
|
@ -6,10 +6,13 @@ package org
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/secret"
|
secret_model "code.gitea.io/gitea/models/secret"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
|
"code.gitea.io/gitea/routers/web/shared/actions"
|
||||||
|
"code.gitea.io/gitea/services/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListActionsSecrets list an organization's actions secrets
|
// ListActionsSecrets list an organization's actions secrets
|
||||||
|
@ -42,18 +45,18 @@ func ListActionsSecrets(ctx *context.APIContext) {
|
||||||
|
|
||||||
// listActionsSecrets list an organization's actions secrets
|
// listActionsSecrets list an organization's actions secrets
|
||||||
func listActionsSecrets(ctx *context.APIContext) {
|
func listActionsSecrets(ctx *context.APIContext) {
|
||||||
opts := &secret.FindSecretsOptions{
|
opts := &secret_model.FindSecretsOptions{
|
||||||
OwnerID: ctx.Org.Organization.ID,
|
OwnerID: ctx.Org.Organization.ID,
|
||||||
ListOptions: utils.GetListOptions(ctx),
|
ListOptions: utils.GetListOptions(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := secret.CountSecrets(ctx, opts)
|
count, err := secret_model.CountSecrets(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets, err := secret.FindSecrets(ctx, *opts)
|
secrets, err := secret_model.FindSecrets(ctx, *opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
@ -70,3 +73,43 @@ func listActionsSecrets(ctx *context.APIContext) {
|
||||||
ctx.SetTotalCountHeader(count)
|
ctx.SetTotalCountHeader(count)
|
||||||
ctx.JSON(http.StatusOK, apiSecrets)
|
ctx.JSON(http.StatusOK, apiSecrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateOrgSecret create one secret of the organization
|
||||||
|
func CreateOrgSecret(ctx *context.APIContext) {
|
||||||
|
// swagger:operation POST /orgs/{org}/actions/secrets organization createOrgSecret
|
||||||
|
// ---
|
||||||
|
// summary: Create a secret in an organization
|
||||||
|
// consumes:
|
||||||
|
// - application/json
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: org
|
||||||
|
// in: path
|
||||||
|
// description: name of organization
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/CreateSecretOption"
|
||||||
|
// responses:
|
||||||
|
// "201":
|
||||||
|
// "$ref": "#/responses/Secret"
|
||||||
|
// "400":
|
||||||
|
// "$ref": "#/responses/error"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
opt := web.GetForm(ctx).(*api.CreateSecretOption)
|
||||||
|
s, err := secret_model.InsertEncryptedSecret(
|
||||||
|
ctx, ctx.Org.Organization.ID, 0, opt.Name, actions.ReserveLineBreakForTextarea(opt.Data),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "InsertEncryptedSecret", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusCreated, convert.ToSecret(s))
|
||||||
|
}
|
||||||
|
|
|
@ -11,3 +11,10 @@ type swaggerResponseSecretList struct {
|
||||||
// in:body
|
// in:body
|
||||||
Body []api.Secret `json:"body"`
|
Body []api.Secret `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secret
|
||||||
|
// swagger:response Secret
|
||||||
|
type swaggerResponseSecret struct {
|
||||||
|
// in:body
|
||||||
|
Body api.Secret `json:"body"`
|
||||||
|
}
|
||||||
|
|
|
@ -187,4 +187,7 @@ type swaggerParameterBodies struct {
|
||||||
|
|
||||||
// in:body
|
// in:body
|
||||||
UpdateRepoAvatarOptions api.UpdateRepoAvatarOption
|
UpdateRepoAvatarOptions api.UpdateRepoAvatarOption
|
||||||
|
|
||||||
|
// in:body
|
||||||
|
CreateSecretOption api.CreateSecretOption
|
||||||
}
|
}
|
||||||
|
|
18
services/convert/secret.go
Normal file
18
services/convert/secret.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
secret_model "code.gitea.io/gitea/models/secret"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToSecret converts Secret to API format
|
||||||
|
func ToSecret(secret *secret_model.Secret) *api.Secret {
|
||||||
|
result := &api.Secret{
|
||||||
|
Name: secret.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
74
templates/swagger/v1_json.tmpl
generated
74
templates/swagger/v1_json.tmpl
generated
|
@ -1586,6 +1586,49 @@
|
||||||
"$ref": "#/responses/SecretList"
|
"$ref": "#/responses/SecretList"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"summary": "Create a secret in an organization",
|
||||||
|
"operationId": "createOrgSecret",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of organization",
|
||||||
|
"name": "org",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/CreateSecretOption"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"$ref": "#/responses/Secret"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"$ref": "#/responses/error"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/orgs/{org}/activities/feeds": {
|
"/orgs/{org}/activities/feeds": {
|
||||||
|
@ -17443,6 +17486,27 @@
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
|
"CreateSecretOption": {
|
||||||
|
"description": "CreateSecretOption options when creating secret",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"description": "Data of the secret to create",
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Data"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "Name of the secret to create",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true,
|
||||||
|
"x-go-name": "Name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
|
},
|
||||||
"CreateStatusOption": {
|
"CreateStatusOption": {
|
||||||
"description": "CreateStatusOption holds the information needed to create a new CommitStatus for a Commit",
|
"description": "CreateStatusOption holds the information needed to create a new CommitStatus for a Commit",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -21334,7 +21398,7 @@
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
"Secret": {
|
"Secret": {
|
||||||
"description": "User represents a secret",
|
"description": "Secret represents a secret",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"created_at": {
|
"created_at": {
|
||||||
|
@ -22921,6 +22985,12 @@
|
||||||
"$ref": "#/definitions/SearchResults"
|
"$ref": "#/definitions/SearchResults"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Secret": {
|
||||||
|
"description": "Secret",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Secret"
|
||||||
|
}
|
||||||
|
},
|
||||||
"SecretList": {
|
"SecretList": {
|
||||||
"description": "SecretList",
|
"description": "SecretList",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
@ -23137,7 +23207,7 @@
|
||||||
"parameterBodies": {
|
"parameterBodies": {
|
||||||
"description": "parameterBodies",
|
"description": "parameterBodies",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/UpdateRepoAvatarOption"
|
"$ref": "#/definitions/CreateSecretOption"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redirect": {
|
"redirect": {
|
||||||
|
|
Loading…
Reference in a new issue