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
2022-05-11 13:09:36 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-11-19 16:39:57 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2017-01-20 09:58:46 +03:00
"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"
2022-06-06 11:01:49 +03:00
repo_service "code.gitea.io/gitea/services/repository"
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 ( )
2022-03-22 10:03:22 +03:00
attach , err := attachment . UploadAttachment ( file , ctx . Doer . 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" )
2022-05-20 17:08:52 +03:00
attach , err := repo_model . GetAttachmentByUUID ( ctx , file )
2019-10-15 15:19:32 +03:00
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
}
2022-03-22 10:03:22 +03:00
if ! ctx . IsSigned || ( ctx . Doer . ID != attach . UploaderID ) {
2021-04-05 18:30:52 +03:00
ctx . Error ( http . StatusForbidden )
2020-02-28 02:10:27 +03:00
return
}
2021-11-19 16:39:57 +03:00
err = repo_model . DeleteAttachment ( attach , true )
2019-10-15 15:19:32 +03:00
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 ) {
2022-05-20 17:08:52 +03:00
attach , err := repo_model . GetAttachmentByUUID ( ctx , ctx . Params ( ":uuid" ) )
2020-01-05 02:20:08 +03:00
if err != nil {
2021-11-19 16:39:57 +03:00
if repo_model . 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
}
2022-06-06 11:01:49 +03:00
repository , unitType , err := repo_service . LinkedRepository ( attach )
2020-01-05 02:20:08 +03:00
if err != nil {
ctx . ServerError ( "LinkedRepository" , err )
return
}
2022-01-20 20:46:10 +03:00
if repository == nil { // If not linked
2022-03-22 10:03:22 +03:00
if ! ( ctx . IsSigned && attach . UploaderID == ctx . Doer . ID ) { // We block if not the uploader
2020-01-05 02:20:08 +03:00
ctx . Error ( http . StatusNotFound )
return
}
2022-01-20 20:46:10 +03:00
} else { // If we have the repository we check access
2022-05-11 13:09:36 +03:00
perm , err := access_model . GetUserRepoPermission ( ctx , repository , ctx . Doer )
2020-01-05 02:20:08 +03:00
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 {
2022-01-20 20:46:10 +03:00
// If we have a signed url (S3, object storage), redirect to this directly.
2020-08-18 07:23:45 +03:00
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
}
2022-01-20 20:46:10 +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
}
}