2018-03-06 02:22:16 +01:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2018-03-06 02:22:16 +01:00
package repo
import (
2019-12-20 18:07:12 +01:00
"net/http"
2018-03-29 21:32:40 +08:00
2021-11-19 21:39:57 +08:00
repo_model "code.gitea.io/gitea/models/repo"
2018-03-06 02:22:16 +01:00
"code.gitea.io/gitea/modules/context"
2019-09-27 04:24:06 +02:00
"code.gitea.io/gitea/modules/log"
2018-03-06 02:22:16 +01:00
"code.gitea.io/gitea/modules/setting"
2019-05-11 18:21:34 +08:00
api "code.gitea.io/gitea/modules/structs"
2019-08-23 09:40:30 -07:00
"code.gitea.io/gitea/modules/upload"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
2021-09-08 23:19:30 +08:00
"code.gitea.io/gitea/services/attachment"
2022-12-29 03:57:15 +01:00
"code.gitea.io/gitea/services/convert"
2018-03-06 02:22:16 +01:00
)
2023-11-26 01:21:21 +08:00
func checkReleaseMatchRepo ( ctx * context . APIContext , releaseID int64 ) bool {
release , err := repo_model . GetReleaseByID ( ctx , releaseID )
if err != nil {
if repo_model . IsErrReleaseNotExist ( err ) {
ctx . NotFound ( )
return false
}
ctx . Error ( http . StatusInternalServerError , "GetReleaseByID" , err )
return false
}
if release . RepoID != ctx . Repo . Repository . ID {
ctx . NotFound ( )
return false
}
return true
}
2018-03-06 02:22:16 +01:00
// GetReleaseAttachment gets a single attachment of the release
func GetReleaseAttachment ( ctx * context . APIContext ) {
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoGetReleaseAttachment
// ---
// summary: Get a release attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the release
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to get
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// responses:
// "200":
// "$ref": "#/responses/Attachment"
2023-09-13 04:37:54 +02:00
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2018-03-06 02:22:16 +01:00
releaseID := ctx . ParamsInt64 ( ":id" )
2023-11-26 01:21:21 +08:00
if ! checkReleaseMatchRepo ( ctx , releaseID ) {
return
}
2023-07-10 17:31:19 +08:00
attachID := ctx . ParamsInt64 ( ":attachment_id" )
2022-05-20 22:08:52 +08:00
attach , err := repo_model . GetAttachmentByID ( ctx , attachID )
2018-03-06 02:22:16 +01:00
if err != nil {
2022-08-24 13:36:21 +01:00
if repo_model . IsErrAttachmentNotExist ( err ) {
ctx . NotFound ( )
return
}
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "GetAttachmentByID" , err )
2018-03-06 02:22:16 +01:00
return
}
if attach . ReleaseID != releaseID {
2019-09-27 04:24:06 +02:00
log . Info ( "User requested attachment is not in release, release_id %v, attachment_id: %v" , releaseID , attachID )
2019-03-18 21:29:43 -05:00
ctx . NotFound ( )
2018-03-06 02:22:16 +01:00
return
}
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
2023-07-10 17:31:19 +08:00
ctx . JSON ( http . StatusOK , convert . ToAPIAttachment ( ctx . Repo . Repository , attach ) )
2018-03-06 02:22:16 +01:00
}
// ListReleaseAttachments lists all attachments of the release
func ListReleaseAttachments ( ctx * context . APIContext ) {
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets repository repoListReleaseAttachments
// ---
// summary: List release's attachments
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the release
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// responses:
// "200":
// "$ref": "#/responses/AttachmentList"
2023-09-13 04:37:54 +02:00
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2018-03-06 02:22:16 +01:00
releaseID := ctx . ParamsInt64 ( ":id" )
2022-08-25 10:31:57 +08:00
release , err := repo_model . GetReleaseByID ( ctx , releaseID )
2018-03-06 02:22:16 +01:00
if err != nil {
2022-08-25 10:31:57 +08:00
if repo_model . IsErrReleaseNotExist ( err ) {
2022-08-24 13:36:21 +01:00
ctx . NotFound ( )
return
}
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "GetReleaseByID" , err )
2018-03-06 02:22:16 +01:00
return
}
if release . RepoID != ctx . Repo . Repository . ID {
2019-03-18 21:29:43 -05:00
ctx . NotFound ( )
2018-03-06 02:22:16 +01:00
return
}
2022-11-19 09:12:33 +01:00
if err := release . LoadAttributes ( ctx ) ; err != nil {
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "LoadAttributes" , err )
2018-03-06 02:22:16 +01:00
return
}
2023-07-10 17:31:19 +08:00
ctx . JSON ( http . StatusOK , convert . ToAPIRelease ( ctx , ctx . Repo . Repository , release ) . Attachments )
2018-03-06 02:22:16 +01:00
}
// CreateReleaseAttachment creates an attachment and saves the given file
func CreateReleaseAttachment ( ctx * context . APIContext ) {
// swagger:operation POST /repos/{owner}/{repo}/releases/{id}/assets repository repoCreateReleaseAttachment
// ---
// summary: Create a release attachment
// produces:
// - application/json
// consumes:
// - multipart/form-data
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the release
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// - name: name
// in: query
// description: name of the attachment
// type: string
// required: false
// - name: attachment
// in: formData
// description: attachment to upload
// type: file
// required: true
// responses:
// "201":
// "$ref": "#/responses/Attachment"
2019-12-20 18:07:12 +01:00
// "400":
// "$ref": "#/responses/error"
2023-09-13 04:37:54 +02:00
// "404":
// "$ref": "#/responses/notFound"
2018-03-06 02:22:16 +01:00
// Check if attachments are enabled
2020-08-18 12:23:45 +08:00
if ! setting . Attachment . Enabled {
2019-03-18 21:29:43 -05:00
ctx . NotFound ( "Attachment is not enabled" )
2018-03-06 02:22:16 +01:00
return
}
// Check if release exists an load release
releaseID := ctx . ParamsInt64 ( ":id" )
2023-11-26 01:21:21 +08:00
if ! checkReleaseMatchRepo ( ctx , releaseID ) {
2018-03-06 02:22:16 +01:00
return
}
// Get uploaded file from request
2021-01-26 23:36:53 +08:00
file , header , err := ctx . Req . FormFile ( "attachment" )
2018-03-06 02:22:16 +01:00
if err != nil {
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "GetFile" , err )
2018-03-06 02:22:16 +01:00
return
}
defer file . Close ( )
2022-01-20 18:46:10 +01:00
filename := header . Filename
2021-08-11 02:31:13 +02:00
if query := ctx . FormString ( "name" ) ; query != "" {
2018-03-06 02:22:16 +01:00
filename = query
}
// Create a new attachment and save the file
2023-10-03 12:30:41 +02:00
attach , err := attachment . UploadAttachment ( ctx , file , setting . Repository . Release . AllowedTypes , header . Size , & repo_model . Attachment {
2022-12-09 07:35:56 +01:00
Name : filename ,
UploaderID : ctx . Doer . ID ,
2023-11-26 01:21:21 +08:00
RepoID : ctx . Repo . Repository . ID ,
2022-12-09 07:35:56 +01:00
ReleaseID : releaseID ,
} )
2018-03-06 02:22:16 +01:00
if err != nil {
2021-09-08 23:19:30 +08:00
if upload . IsErrFileTypeForbidden ( err ) {
ctx . Error ( http . StatusBadRequest , "DetectContentType" , err )
return
}
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "NewAttachment" , err )
2018-03-06 02:22:16 +01:00
return
}
2019-04-03 03:25:05 +08:00
2023-07-10 17:31:19 +08:00
ctx . JSON ( http . StatusCreated , convert . ToAPIAttachment ( ctx . Repo . Repository , attach ) )
2018-03-06 02:22:16 +01:00
}
// EditReleaseAttachment updates the given attachment
2021-01-26 23:36:53 +08:00
func EditReleaseAttachment ( ctx * context . APIContext ) {
2018-03-06 02:22:16 +01:00
// swagger:operation PATCH /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoEditReleaseAttachment
// ---
// summary: Edit a release attachment
// produces:
// - application/json
// consumes:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the release
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to edit
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditAttachmentOptions"
// responses:
// "201":
// "$ref": "#/responses/Attachment"
2023-09-13 04:37:54 +02:00
// "404":
// "$ref": "#/responses/notFound"
2018-03-06 02:22:16 +01:00
2021-01-26 23:36:53 +08:00
form := web . GetForm ( ctx ) . ( * api . EditAttachmentOptions )
2018-03-06 02:22:16 +01:00
// Check if release exists an load release
releaseID := ctx . ParamsInt64 ( ":id" )
2023-11-26 01:21:21 +08:00
if ! checkReleaseMatchRepo ( ctx , releaseID ) {
return
}
2023-07-10 17:31:19 +08:00
attachID := ctx . ParamsInt64 ( ":attachment_id" )
2022-05-20 22:08:52 +08:00
attach , err := repo_model . GetAttachmentByID ( ctx , attachID )
2018-03-06 02:22:16 +01:00
if err != nil {
2022-08-24 13:36:21 +01:00
if repo_model . IsErrAttachmentNotExist ( err ) {
ctx . NotFound ( )
return
}
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "GetAttachmentByID" , err )
2018-03-06 02:22:16 +01:00
return
}
if attach . ReleaseID != releaseID {
2019-09-27 04:24:06 +02:00
log . Info ( "User requested attachment is not in release, release_id %v, attachment_id: %v" , releaseID , attachID )
2019-03-18 21:29:43 -05:00
ctx . NotFound ( )
2018-03-06 02:22:16 +01:00
return
}
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
if form . Name != "" {
attach . Name = form . Name
}
2022-05-20 22:08:52 +08:00
if err := repo_model . UpdateAttachment ( ctx , attach ) ; err != nil {
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "UpdateAttachment" , attach )
2018-03-06 02:22:16 +01:00
}
2023-07-10 17:31:19 +08:00
ctx . JSON ( http . StatusCreated , convert . ToAPIAttachment ( ctx . Repo . Repository , attach ) )
2018-03-06 02:22:16 +01:00
}
// DeleteReleaseAttachment delete a given attachment
func DeleteReleaseAttachment ( ctx * context . APIContext ) {
// swagger:operation DELETE /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoDeleteReleaseAttachment
// ---
// summary: Delete a release attachment
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the release
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// - name: attachment_id
// in: path
// description: id of the attachment to delete
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2018-03-06 02:22:16 +01:00
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
2023-09-13 04:37:54 +02:00
// "404":
// "$ref": "#/responses/notFound"
2018-03-06 02:22:16 +01:00
// Check if release exists an load release
releaseID := ctx . ParamsInt64 ( ":id" )
2023-11-26 01:21:21 +08:00
if ! checkReleaseMatchRepo ( ctx , releaseID ) {
return
}
2023-07-10 17:31:19 +08:00
attachID := ctx . ParamsInt64 ( ":attachment_id" )
2022-05-20 22:08:52 +08:00
attach , err := repo_model . GetAttachmentByID ( ctx , attachID )
2018-03-06 02:22:16 +01:00
if err != nil {
2022-08-24 13:36:21 +01:00
if repo_model . IsErrAttachmentNotExist ( err ) {
ctx . NotFound ( )
return
}
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "GetAttachmentByID" , err )
2018-03-06 02:22:16 +01:00
return
}
if attach . ReleaseID != releaseID {
2019-09-27 04:24:06 +02:00
log . Info ( "User requested attachment is not in release, release_id %v, attachment_id: %v" , releaseID , attachID )
2019-03-18 21:29:43 -05:00
ctx . NotFound ( )
2018-03-06 02:22:16 +01:00
return
}
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests
2023-09-15 08:13:19 +02:00
if err := repo_model . DeleteAttachment ( ctx , attach , true ) ; err != nil {
2019-12-20 18:07:12 +01:00
ctx . Error ( http . StatusInternalServerError , "DeleteAttachment" , err )
2018-03-06 02:22:16 +01:00
return
}
2019-12-20 18:07:12 +01:00
ctx . Status ( http . StatusNoContent )
2018-03-06 02:22:16 +01:00
}