code.gitea.io/gitea@v1.21.7/routers/api/v1/repo/patch.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package repo
     5  
     6  import (
     7  	"net/http"
     8  	"time"
     9  
    10  	"code.gitea.io/gitea/models"
    11  	git_model "code.gitea.io/gitea/models/git"
    12  	repo_model "code.gitea.io/gitea/models/repo"
    13  	"code.gitea.io/gitea/modules/context"
    14  	"code.gitea.io/gitea/modules/git"
    15  	api "code.gitea.io/gitea/modules/structs"
    16  	"code.gitea.io/gitea/modules/web"
    17  	"code.gitea.io/gitea/services/repository/files"
    18  )
    19  
    20  // ApplyDiffPatch handles API call for applying a patch
    21  func ApplyDiffPatch(ctx *context.APIContext) {
    22  	// swagger:operation POST /repos/{owner}/{repo}/diffpatch repository repoApplyDiffPatch
    23  	// ---
    24  	// summary: Apply diff patch to repository
    25  	// consumes:
    26  	// - application/json
    27  	// produces:
    28  	// - application/json
    29  	// parameters:
    30  	// - name: owner
    31  	//   in: path
    32  	//   description: owner of the repo
    33  	//   type: string
    34  	//   required: true
    35  	// - name: repo
    36  	//   in: path
    37  	//   description: name of the repo
    38  	//   type: string
    39  	//   required: true
    40  	// - name: body
    41  	//   in: body
    42  	//   required: true
    43  	//   schema:
    44  	//     "$ref": "#/definitions/UpdateFileOptions"
    45  	// responses:
    46  	//   "200":
    47  	//     "$ref": "#/responses/FileResponse"
    48  	//   "404":
    49  	//     "$ref": "#/responses/notFound"
    50  	apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions)
    51  
    52  	opts := &files.ApplyDiffPatchOptions{
    53  		Content:   apiOpts.Content,
    54  		SHA:       apiOpts.SHA,
    55  		Message:   apiOpts.Message,
    56  		OldBranch: apiOpts.BranchName,
    57  		NewBranch: apiOpts.NewBranchName,
    58  		Committer: &files.IdentityOptions{
    59  			Name:  apiOpts.Committer.Name,
    60  			Email: apiOpts.Committer.Email,
    61  		},
    62  		Author: &files.IdentityOptions{
    63  			Name:  apiOpts.Author.Name,
    64  			Email: apiOpts.Author.Email,
    65  		},
    66  		Dates: &files.CommitDateOptions{
    67  			Author:    apiOpts.Dates.Author,
    68  			Committer: apiOpts.Dates.Committer,
    69  		},
    70  		Signoff: apiOpts.Signoff,
    71  	}
    72  	if opts.Dates.Author.IsZero() {
    73  		opts.Dates.Author = time.Now()
    74  	}
    75  	if opts.Dates.Committer.IsZero() {
    76  		opts.Dates.Committer = time.Now()
    77  	}
    78  
    79  	if opts.Message == "" {
    80  		opts.Message = "apply-patch"
    81  	}
    82  
    83  	if !canWriteFiles(ctx, apiOpts.BranchName) {
    84  		ctx.Error(http.StatusInternalServerError, "ApplyPatch", repo_model.ErrUserDoesNotHaveAccessToRepo{
    85  			UserID:   ctx.Doer.ID,
    86  			RepoName: ctx.Repo.Repository.LowerName,
    87  		})
    88  		return
    89  	}
    90  
    91  	fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts)
    92  	if err != nil {
    93  		if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) {
    94  			ctx.Error(http.StatusForbidden, "Access", err)
    95  			return
    96  		}
    97  		if git_model.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) ||
    98  			models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) {
    99  			ctx.Error(http.StatusUnprocessableEntity, "Invalid", err)
   100  			return
   101  		}
   102  		if git_model.IsErrBranchNotExist(err) || git.IsErrBranchNotExist(err) {
   103  			ctx.Error(http.StatusNotFound, "BranchDoesNotExist", err)
   104  			return
   105  		}
   106  		ctx.Error(http.StatusInternalServerError, "ApplyPatch", err)
   107  	} else {
   108  		ctx.JSON(http.StatusCreated, fileResponse)
   109  	}
   110  }