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 }