code.gitea.io/gitea@v1.22.3/routers/api/v1/org/action.go (about)

     1  // Copyright 2024 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package org
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  
    10  	actions_model "code.gitea.io/gitea/models/actions"
    11  	"code.gitea.io/gitea/models/db"
    12  	secret_model "code.gitea.io/gitea/models/secret"
    13  	api "code.gitea.io/gitea/modules/structs"
    14  	"code.gitea.io/gitea/modules/util"
    15  	"code.gitea.io/gitea/modules/web"
    16  	"code.gitea.io/gitea/routers/api/v1/shared"
    17  	"code.gitea.io/gitea/routers/api/v1/utils"
    18  	actions_service "code.gitea.io/gitea/services/actions"
    19  	"code.gitea.io/gitea/services/context"
    20  	secret_service "code.gitea.io/gitea/services/secrets"
    21  )
    22  
    23  // ListActionsSecrets list an organization's actions secrets
    24  func (Action) ListActionsSecrets(ctx *context.APIContext) {
    25  	// swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets
    26  	// ---
    27  	// summary: List an organization's actions secrets
    28  	// produces:
    29  	// - application/json
    30  	// parameters:
    31  	// - name: org
    32  	//   in: path
    33  	//   description: name of the organization
    34  	//   type: string
    35  	//   required: true
    36  	// - name: page
    37  	//   in: query
    38  	//   description: page number of results to return (1-based)
    39  	//   type: integer
    40  	// - name: limit
    41  	//   in: query
    42  	//   description: page size of results
    43  	//   type: integer
    44  	// responses:
    45  	//   "200":
    46  	//     "$ref": "#/responses/SecretList"
    47  	//   "404":
    48  	//     "$ref": "#/responses/notFound"
    49  
    50  	opts := &secret_model.FindSecretsOptions{
    51  		OwnerID:     ctx.Org.Organization.ID,
    52  		ListOptions: utils.GetListOptions(ctx),
    53  	}
    54  
    55  	secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts)
    56  	if err != nil {
    57  		ctx.InternalServerError(err)
    58  		return
    59  	}
    60  
    61  	apiSecrets := make([]*api.Secret, len(secrets))
    62  	for k, v := range secrets {
    63  		apiSecrets[k] = &api.Secret{
    64  			Name:    v.Name,
    65  			Created: v.CreatedUnix.AsTime(),
    66  		}
    67  	}
    68  
    69  	ctx.SetTotalCountHeader(count)
    70  	ctx.JSON(http.StatusOK, apiSecrets)
    71  }
    72  
    73  // create or update one secret of the organization
    74  func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
    75  	// swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
    76  	// ---
    77  	// summary: Create or Update a secret value in an organization
    78  	// consumes:
    79  	// - application/json
    80  	// produces:
    81  	// - application/json
    82  	// parameters:
    83  	// - name: org
    84  	//   in: path
    85  	//   description: name of organization
    86  	//   type: string
    87  	//   required: true
    88  	// - name: secretname
    89  	//   in: path
    90  	//   description: name of the secret
    91  	//   type: string
    92  	//   required: true
    93  	// - name: body
    94  	//   in: body
    95  	//   schema:
    96  	//     "$ref": "#/definitions/CreateOrUpdateSecretOption"
    97  	// responses:
    98  	//   "201":
    99  	//     description: response when creating a secret
   100  	//   "204":
   101  	//     description: response when updating a secret
   102  	//   "400":
   103  	//     "$ref": "#/responses/error"
   104  	//   "404":
   105  	//     "$ref": "#/responses/notFound"
   106  
   107  	opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
   108  
   109  	_, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data)
   110  	if err != nil {
   111  		if errors.Is(err, util.ErrInvalidArgument) {
   112  			ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
   113  		} else if errors.Is(err, util.ErrNotExist) {
   114  			ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err)
   115  		} else {
   116  			ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
   117  		}
   118  		return
   119  	}
   120  
   121  	if created {
   122  		ctx.Status(http.StatusCreated)
   123  	} else {
   124  		ctx.Status(http.StatusNoContent)
   125  	}
   126  }
   127  
   128  // DeleteSecret delete one secret of the organization
   129  func (Action) DeleteSecret(ctx *context.APIContext) {
   130  	// swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret
   131  	// ---
   132  	// summary: Delete a secret in an organization
   133  	// consumes:
   134  	// - application/json
   135  	// produces:
   136  	// - application/json
   137  	// parameters:
   138  	// - name: org
   139  	//   in: path
   140  	//   description: name of organization
   141  	//   type: string
   142  	//   required: true
   143  	// - name: secretname
   144  	//   in: path
   145  	//   description: name of the secret
   146  	//   type: string
   147  	//   required: true
   148  	// responses:
   149  	//   "204":
   150  	//     description: delete one secret of the organization
   151  	//   "400":
   152  	//     "$ref": "#/responses/error"
   153  	//   "404":
   154  	//     "$ref": "#/responses/notFound"
   155  
   156  	err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"))
   157  	if err != nil {
   158  		if errors.Is(err, util.ErrInvalidArgument) {
   159  			ctx.Error(http.StatusBadRequest, "DeleteSecret", err)
   160  		} else if errors.Is(err, util.ErrNotExist) {
   161  			ctx.Error(http.StatusNotFound, "DeleteSecret", err)
   162  		} else {
   163  			ctx.Error(http.StatusInternalServerError, "DeleteSecret", err)
   164  		}
   165  		return
   166  	}
   167  
   168  	ctx.Status(http.StatusNoContent)
   169  }
   170  
   171  // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
   172  // GetRegistrationToken returns the token to register org runners
   173  func (Action) GetRegistrationToken(ctx *context.APIContext) {
   174  	// swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
   175  	// ---
   176  	// summary: Get an organization's actions runner registration token
   177  	// produces:
   178  	// - application/json
   179  	// parameters:
   180  	// - name: org
   181  	//   in: path
   182  	//   description: name of the organization
   183  	//   type: string
   184  	//   required: true
   185  	// responses:
   186  	//   "200":
   187  	//     "$ref": "#/responses/RegistrationToken"
   188  
   189  	shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
   190  }
   191  
   192  // ListVariables list org-level variables
   193  func (Action) ListVariables(ctx *context.APIContext) {
   194  	// swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList
   195  	// ---
   196  	// summary: Get an org-level variables list
   197  	// produces:
   198  	// - application/json
   199  	// parameters:
   200  	// - name: org
   201  	//   in: path
   202  	//   description: name of the organization
   203  	//   type: string
   204  	//   required: true
   205  	// - name: page
   206  	//   in: query
   207  	//   description: page number of results to return (1-based)
   208  	//   type: integer
   209  	// - name: limit
   210  	//   in: query
   211  	//   description: page size of results
   212  	//   type: integer
   213  	// responses:
   214  	//   "200":
   215  	//		 "$ref": "#/responses/VariableList"
   216  	//   "400":
   217  	//     "$ref": "#/responses/error"
   218  	//   "404":
   219  	//     "$ref": "#/responses/notFound"
   220  
   221  	vars, count, err := db.FindAndCount[actions_model.ActionVariable](ctx, &actions_model.FindVariablesOpts{
   222  		OwnerID:     ctx.Org.Organization.ID,
   223  		ListOptions: utils.GetListOptions(ctx),
   224  	})
   225  	if err != nil {
   226  		ctx.Error(http.StatusInternalServerError, "FindVariables", err)
   227  		return
   228  	}
   229  
   230  	variables := make([]*api.ActionVariable, len(vars))
   231  	for i, v := range vars {
   232  		variables[i] = &api.ActionVariable{
   233  			OwnerID: v.OwnerID,
   234  			RepoID:  v.RepoID,
   235  			Name:    v.Name,
   236  			Data:    v.Data,
   237  		}
   238  	}
   239  
   240  	ctx.SetTotalCountHeader(count)
   241  	ctx.JSON(http.StatusOK, variables)
   242  }
   243  
   244  // GetVariable get an org-level variable
   245  func (Action) GetVariable(ctx *context.APIContext) {
   246  	// swagger:operation GET /orgs/{org}/actions/variables/{variablename} organization getOrgVariable
   247  	// ---
   248  	// summary: Get an org-level variable
   249  	// produces:
   250  	// - application/json
   251  	// parameters:
   252  	// - name: org
   253  	//   in: path
   254  	//   description: name of the organization
   255  	//   type: string
   256  	//   required: true
   257  	// - name: variablename
   258  	//   in: path
   259  	//   description: name of the variable
   260  	//   type: string
   261  	//   required: true
   262  	// responses:
   263  	//   "200":
   264  	//		 "$ref": "#/responses/ActionVariable"
   265  	//   "400":
   266  	//     "$ref": "#/responses/error"
   267  	//   "404":
   268  	//     "$ref": "#/responses/notFound"
   269  
   270  	v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
   271  		OwnerID: ctx.Org.Organization.ID,
   272  		Name:    ctx.Params("variablename"),
   273  	})
   274  	if err != nil {
   275  		if errors.Is(err, util.ErrNotExist) {
   276  			ctx.Error(http.StatusNotFound, "GetVariable", err)
   277  		} else {
   278  			ctx.Error(http.StatusInternalServerError, "GetVariable", err)
   279  		}
   280  		return
   281  	}
   282  
   283  	variable := &api.ActionVariable{
   284  		OwnerID: v.OwnerID,
   285  		RepoID:  v.RepoID,
   286  		Name:    v.Name,
   287  		Data:    v.Data,
   288  	}
   289  
   290  	ctx.JSON(http.StatusOK, variable)
   291  }
   292  
   293  // DeleteVariable delete an org-level variable
   294  func (Action) DeleteVariable(ctx *context.APIContext) {
   295  	// swagger:operation DELETE /orgs/{org}/actions/variables/{variablename} organization deleteOrgVariable
   296  	// ---
   297  	// summary: Delete an org-level variable
   298  	// produces:
   299  	// - application/json
   300  	// parameters:
   301  	// - name: org
   302  	//   in: path
   303  	//   description: name of the organization
   304  	//   type: string
   305  	//   required: true
   306  	// - name: variablename
   307  	//   in: path
   308  	//   description: name of the variable
   309  	//   type: string
   310  	//   required: true
   311  	// responses:
   312  	//   "200":
   313  	//			"$ref": "#/responses/ActionVariable"
   314  	//   "201":
   315  	//     description: response when deleting a variable
   316  	//   "204":
   317  	//     description: response when deleting a variable
   318  	//   "400":
   319  	//     "$ref": "#/responses/error"
   320  	//   "404":
   321  	//     "$ref": "#/responses/notFound"
   322  
   323  	if err := actions_service.DeleteVariableByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("variablename")); err != nil {
   324  		if errors.Is(err, util.ErrInvalidArgument) {
   325  			ctx.Error(http.StatusBadRequest, "DeleteVariableByName", err)
   326  		} else if errors.Is(err, util.ErrNotExist) {
   327  			ctx.Error(http.StatusNotFound, "DeleteVariableByName", err)
   328  		} else {
   329  			ctx.Error(http.StatusInternalServerError, "DeleteVariableByName", err)
   330  		}
   331  		return
   332  	}
   333  
   334  	ctx.Status(http.StatusNoContent)
   335  }
   336  
   337  // CreateVariable create an org-level variable
   338  func (Action) CreateVariable(ctx *context.APIContext) {
   339  	// swagger:operation POST /orgs/{org}/actions/variables/{variablename} organization createOrgVariable
   340  	// ---
   341  	// summary: Create an org-level variable
   342  	// consumes:
   343  	// - application/json
   344  	// produces:
   345  	// - application/json
   346  	// parameters:
   347  	// - name: org
   348  	//   in: path
   349  	//   description: name of the organization
   350  	//   type: string
   351  	//   required: true
   352  	// - name: variablename
   353  	//   in: path
   354  	//   description: name of the variable
   355  	//   type: string
   356  	//   required: true
   357  	// - name: body
   358  	//   in: body
   359  	//   schema:
   360  	//     "$ref": "#/definitions/CreateVariableOption"
   361  	// responses:
   362  	//   "201":
   363  	//     description: response when creating an org-level variable
   364  	//   "204":
   365  	//     description: response when creating an org-level variable
   366  	//   "400":
   367  	//     "$ref": "#/responses/error"
   368  	//   "404":
   369  	//     "$ref": "#/responses/notFound"
   370  
   371  	opt := web.GetForm(ctx).(*api.CreateVariableOption)
   372  
   373  	ownerID := ctx.Org.Organization.ID
   374  	variableName := ctx.Params("variablename")
   375  
   376  	v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
   377  		OwnerID: ownerID,
   378  		Name:    variableName,
   379  	})
   380  	if err != nil && !errors.Is(err, util.ErrNotExist) {
   381  		ctx.Error(http.StatusInternalServerError, "GetVariable", err)
   382  		return
   383  	}
   384  	if v != nil && v.ID > 0 {
   385  		ctx.Error(http.StatusConflict, "VariableNameAlreadyExists", util.NewAlreadyExistErrorf("variable name %s already exists", variableName))
   386  		return
   387  	}
   388  
   389  	if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value); err != nil {
   390  		if errors.Is(err, util.ErrInvalidArgument) {
   391  			ctx.Error(http.StatusBadRequest, "CreateVariable", err)
   392  		} else {
   393  			ctx.Error(http.StatusInternalServerError, "CreateVariable", err)
   394  		}
   395  		return
   396  	}
   397  
   398  	ctx.Status(http.StatusNoContent)
   399  }
   400  
   401  // UpdateVariable update an org-level variable
   402  func (Action) UpdateVariable(ctx *context.APIContext) {
   403  	// swagger:operation PUT /orgs/{org}/actions/variables/{variablename} organization updateOrgVariable
   404  	// ---
   405  	// summary: Update an org-level variable
   406  	// consumes:
   407  	// - application/json
   408  	// produces:
   409  	// - application/json
   410  	// parameters:
   411  	// - name: org
   412  	//   in: path
   413  	//   description: name of the organization
   414  	//   type: string
   415  	//   required: true
   416  	// - name: variablename
   417  	//   in: path
   418  	//   description: name of the variable
   419  	//   type: string
   420  	//   required: true
   421  	// - name: body
   422  	//   in: body
   423  	//   schema:
   424  	//     "$ref": "#/definitions/UpdateVariableOption"
   425  	// responses:
   426  	//   "201":
   427  	//     description: response when updating an org-level variable
   428  	//   "204":
   429  	//     description: response when updating an org-level variable
   430  	//   "400":
   431  	//     "$ref": "#/responses/error"
   432  	//   "404":
   433  	//     "$ref": "#/responses/notFound"
   434  
   435  	opt := web.GetForm(ctx).(*api.UpdateVariableOption)
   436  
   437  	v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
   438  		OwnerID: ctx.Org.Organization.ID,
   439  		Name:    ctx.Params("variablename"),
   440  	})
   441  	if err != nil {
   442  		if errors.Is(err, util.ErrNotExist) {
   443  			ctx.Error(http.StatusNotFound, "GetVariable", err)
   444  		} else {
   445  			ctx.Error(http.StatusInternalServerError, "GetVariable", err)
   446  		}
   447  		return
   448  	}
   449  
   450  	if opt.Name == "" {
   451  		opt.Name = ctx.Params("variablename")
   452  	}
   453  	if _, err := actions_service.UpdateVariable(ctx, v.ID, opt.Name, opt.Value); err != nil {
   454  		if errors.Is(err, util.ErrInvalidArgument) {
   455  			ctx.Error(http.StatusBadRequest, "UpdateVariable", err)
   456  		} else {
   457  			ctx.Error(http.StatusInternalServerError, "UpdateVariable", err)
   458  		}
   459  		return
   460  	}
   461  
   462  	ctx.Status(http.StatusNoContent)
   463  }
   464  
   465  var _ actions_service.API = new(Action)
   466  
   467  // Action implements actions_service.API
   468  type Action struct{}
   469  
   470  // NewAction creates a new Action service
   471  func NewAction() actions_service.API {
   472  	return Action{}
   473  }