2017-01-20 09:58:46 +03:00
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"fmt"
2020-01-05 02:20:08 +03:00
"net/http"
2017-01-20 09:58:46 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
2021-04-12 17:49:26 +03:00
"code.gitea.io/gitea/modules/httpcache"
2017-01-20 09:58:46 +03:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2020-08-18 07:23:45 +03:00
"code.gitea.io/gitea/modules/storage"
2019-07-07 05:25:05 +03:00
"code.gitea.io/gitea/modules/upload"
2021-06-09 02:33:54 +03:00
"code.gitea.io/gitea/routers/common"
2021-09-08 18:19:30 +03:00
"code.gitea.io/gitea/services/attachment"
2017-01-20 09:58:46 +03:00
)
2020-10-05 08:49:33 +03:00
// UploadIssueAttachment response for Issue/PR attachments
func UploadIssueAttachment ( ctx * context . Context ) {
2021-09-08 18:19:30 +03:00
uploadAttachment ( ctx , ctx . Repo . Repository . ID , setting . Attachment . AllowedTypes )
2017-01-20 09:58:46 +03:00
}
2020-10-05 08:49:33 +03:00
// UploadReleaseAttachment response for uploading release attachments
func UploadReleaseAttachment ( ctx * context . Context ) {
2021-09-08 18:19:30 +03:00
uploadAttachment ( ctx , ctx . Repo . Repository . ID , setting . Repository . Release . AllowedTypes )
2020-10-05 08:49:33 +03:00
}
// UploadAttachment response for uploading attachments
2021-09-08 18:19:30 +03:00
func uploadAttachment ( ctx * context . Context , repoID int64 , allowedTypes string ) {
2020-08-18 07:23:45 +03:00
if ! setting . Attachment . Enabled {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusNotFound , "attachment is not enabled" )
2017-01-20 09:58:46 +03:00
return
}
file , header , err := ctx . Req . FormFile ( "file" )
if err != nil {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "FormFile: %v" , err ) )
2017-01-20 09:58:46 +03:00
return
}
defer file . Close ( )
2021-09-08 18:19:30 +03:00
attach , err := attachment . UploadAttachment ( file , ctx . User . ID , repoID , 0 , header . Filename , allowedTypes )
2017-01-20 09:58:46 +03:00
if err != nil {
2021-09-08 18:19:30 +03:00
if upload . IsErrFileTypeForbidden ( err ) {
ctx . Error ( http . StatusBadRequest , err . Error ( ) )
return
}
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "NewAttachment: %v" , err ) )
2017-01-20 09:58:46 +03:00
return
}
log . Trace ( "New attachment uploaded: %s" , attach . UUID )
2021-04-05 18:30:52 +03:00
ctx . JSON ( http . StatusOK , map [ string ] string {
2017-01-20 09:58:46 +03:00
"uuid" : attach . UUID ,
} )
}
2019-10-15 15:19:32 +03:00
// DeleteAttachment response for deleting issue's attachment
func DeleteAttachment ( ctx * context . Context ) {
2021-08-11 03:31:13 +03:00
file := ctx . FormString ( "file" )
2019-10-15 15:19:32 +03:00
attach , err := models . GetAttachmentByUUID ( file )
if err != nil {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusBadRequest , err . Error ( ) )
2019-10-15 15:19:32 +03:00
return
}
2020-02-28 02:10:27 +03:00
if ! ctx . IsSigned || ( ctx . User . ID != attach . UploaderID ) {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusForbidden )
2020-02-28 02:10:27 +03:00
return
}
2019-10-15 15:19:32 +03:00
err = models . DeleteAttachment ( attach , true )
if err != nil {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "DeleteAttachment: %v" , err ) )
2019-10-15 15:19:32 +03:00
return
}
2021-04-05 18:30:52 +03:00
ctx . JSON ( http . StatusOK , map [ string ] string {
2019-10-15 15:19:32 +03:00
"uuid" : attach . UUID ,
} )
}
2020-01-05 02:20:08 +03:00
// GetAttachment serve attachements
func GetAttachment ( ctx * context . Context ) {
attach , err := models . GetAttachmentByUUID ( ctx . Params ( ":uuid" ) )
if err != nil {
if models . IsErrAttachmentNotExist ( err ) {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusNotFound )
2020-01-05 02:20:08 +03:00
} else {
ctx . ServerError ( "GetAttachmentByUUID" , err )
}
return
}
repository , unitType , err := attach . LinkedRepository ( )
if err != nil {
ctx . ServerError ( "LinkedRepository" , err )
return
}
if repository == nil { //If not linked
if ! ( ctx . IsSigned && attach . UploaderID == ctx . User . ID ) { //We block if not the uploader
ctx . Error ( http . StatusNotFound )
return
}
} else { //If we have the repository we check access
perm , err := models . GetUserRepoPermission ( repository , ctx . User )
if err != nil {
ctx . Error ( http . StatusInternalServerError , "GetUserRepoPermission" , err . Error ( ) )
return
}
if ! perm . CanRead ( unitType ) {
ctx . Error ( http . StatusNotFound )
return
}
}
2021-04-12 17:49:26 +03:00
if err := attach . IncreaseDownloadCount ( ) ; err != nil {
ctx . ServerError ( "IncreaseDownloadCount" , err )
return
}
2020-08-18 07:23:45 +03:00
if setting . Attachment . ServeDirect {
//If we have a signed url (S3, object storage), redirect to this directly.
u , err := storage . Attachments . URL ( attach . RelativePath ( ) , attach . Name )
if u != nil && err == nil {
ctx . Redirect ( u . String ( ) )
return
}
}
2021-04-12 17:49:26 +03:00
if httpcache . HandleGenericETagCache ( ctx . Req , ctx . Resp , ` " ` + attach . UUID + ` " ` ) {
return
}
2020-01-05 02:20:08 +03:00
//If we have matched and access to release or issue
2020-08-18 07:23:45 +03:00
fr , err := storage . Attachments . Open ( attach . RelativePath ( ) )
2020-01-05 02:20:08 +03:00
if err != nil {
ctx . ServerError ( "Open" , err )
return
}
defer fr . Close ( )
2021-06-09 02:33:54 +03:00
if err = common . ServeData ( ctx , attach . Name , attach . Size , fr ) ; err != nil {
2020-01-05 02:20:08 +03:00
ctx . ServerError ( "ServeData" , err )
return
}
}