2017-01-20 06:58:46 +00:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2017-01-20 06:58:46 +00:00
package repo
import (
"fmt"
2020-01-05 00:20:08 +01:00
"net/http"
2017-01-20 06:58:46 +00:00
2022-05-11 18:09:36 +08:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-11-19 21:39:57 +08:00
repo_model "code.gitea.io/gitea/models/repo"
2021-04-12 16:49:26 +02:00
"code.gitea.io/gitea/modules/httpcache"
2017-01-20 06:58:46 +00:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2020-08-18 12:23:45 +08:00
"code.gitea.io/gitea/modules/storage"
2023-07-07 07:31:56 +02:00
"code.gitea.io/gitea/modules/util"
2021-06-09 07:33:54 +08:00
"code.gitea.io/gitea/routers/common"
2021-09-08 23:19:30 +08:00
"code.gitea.io/gitea/services/attachment"
2024-02-27 15:12:22 +08:00
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/context/upload"
2022-06-06 16:01:49 +08:00
repo_service "code.gitea.io/gitea/services/repository"
2017-01-20 06:58:46 +00:00
)
2020-10-05 07:49:33 +02:00
// UploadIssueAttachment response for Issue/PR attachments
func UploadIssueAttachment ( ctx * context . Context ) {
2021-09-08 23:19:30 +08:00
uploadAttachment ( ctx , ctx . Repo . Repository . ID , setting . Attachment . AllowedTypes )
2017-01-20 06:58:46 +00:00
}
2020-10-05 07:49:33 +02:00
// UploadReleaseAttachment response for uploading release attachments
func UploadReleaseAttachment ( ctx * context . Context ) {
2021-09-08 23:19:30 +08:00
uploadAttachment ( ctx , ctx . Repo . Repository . ID , setting . Repository . Release . AllowedTypes )
2020-10-05 07:49:33 +02:00
}
// UploadAttachment response for uploading attachments
2021-09-08 23:19:30 +08:00
func uploadAttachment ( ctx * context . Context , repoID int64 , allowedTypes string ) {
2020-08-18 12:23:45 +08:00
if ! setting . Attachment . Enabled {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusNotFound , "attachment is not enabled" )
2017-01-20 06:58:46 +00:00
return
}
file , header , err := ctx . Req . FormFile ( "file" )
if err != nil {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "FormFile: %v" , err ) )
2017-01-20 06:58:46 +00:00
return
}
defer file . Close ( )
2023-10-03 12:30:41 +02:00
attach , err := attachment . UploadAttachment ( ctx , file , allowedTypes , header . Size , & repo_model . Attachment {
2022-12-09 07:35:56 +01:00
Name : header . Filename ,
UploaderID : ctx . Doer . ID ,
RepoID : repoID ,
} )
2017-01-20 06:58:46 +00:00
if err != nil {
2021-09-08 23:19:30 +08:00
if upload . IsErrFileTypeForbidden ( err ) {
ctx . Error ( http . StatusBadRequest , err . Error ( ) )
return
}
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "NewAttachment: %v" , err ) )
2017-01-20 06:58:46 +00:00
return
}
log . Trace ( "New attachment uploaded: %s" , attach . UUID )
2021-04-05 17:30:52 +02:00
ctx . JSON ( http . StatusOK , map [ string ] string {
2017-01-20 06:58:46 +00:00
"uuid" : attach . UUID ,
} )
}
2019-10-15 20:19:32 +08:00
// DeleteAttachment response for deleting issue's attachment
func DeleteAttachment ( ctx * context . Context ) {
2021-08-11 02:31:13 +02:00
file := ctx . FormString ( "file" )
2022-05-20 22:08:52 +08:00
attach , err := repo_model . GetAttachmentByUUID ( ctx , file )
2019-10-15 20:19:32 +08:00
if err != nil {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusBadRequest , err . Error ( ) )
2019-10-15 20:19:32 +08:00
return
}
2022-03-22 08:03:22 +01:00
if ! ctx . IsSigned || ( ctx . Doer . ID != attach . UploaderID ) {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusForbidden )
2020-02-28 00:10:27 +01:00
return
}
2023-09-15 08:13:19 +02:00
err = repo_model . DeleteAttachment ( ctx , attach , true )
2019-10-15 20:19:32 +08:00
if err != nil {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusInternalServerError , fmt . Sprintf ( "DeleteAttachment: %v" , err ) )
2019-10-15 20:19:32 +08:00
return
}
2021-04-05 17:30:52 +02:00
ctx . JSON ( http . StatusOK , map [ string ] string {
2019-10-15 20:19:32 +08:00
"uuid" : attach . UUID ,
} )
}
2020-01-05 00:20:08 +01:00
2023-04-12 11:05:23 +02:00
// GetAttachment serve attachments with the given UUID
func ServeAttachment ( ctx * context . Context , uuid string ) {
attach , err := repo_model . GetAttachmentByUUID ( ctx , uuid )
2020-01-05 00:20:08 +01:00
if err != nil {
2021-11-19 21:39:57 +08:00
if repo_model . IsErrAttachmentNotExist ( err ) {
2021-04-05 17:30:52 +02:00
ctx . Error ( http . StatusNotFound )
2020-01-05 00:20:08 +01:00
} else {
ctx . ServerError ( "GetAttachmentByUUID" , err )
}
return
}
2022-12-03 10:48:26 +08:00
repository , unitType , err := repo_service . LinkedRepository ( ctx , attach )
2020-01-05 00:20:08 +01:00
if err != nil {
ctx . ServerError ( "LinkedRepository" , err )
return
}
2022-01-20 18:46:10 +01:00
if repository == nil { // If not linked
2022-03-22 08:03:22 +01:00
if ! ( ctx . IsSigned && attach . UploaderID == ctx . Doer . ID ) { // We block if not the uploader
2020-01-05 00:20:08 +01:00
ctx . Error ( http . StatusNotFound )
return
}
2022-01-20 18:46:10 +01:00
} else { // If we have the repository we check access
2022-05-11 18:09:36 +08:00
perm , err := access_model . GetUserRepoPermission ( ctx , repository , ctx . Doer )
2020-01-05 00:20:08 +01:00
if err != nil {
ctx . Error ( http . StatusInternalServerError , "GetUserRepoPermission" , err . Error ( ) )
return
}
if ! perm . CanRead ( unitType ) {
ctx . Error ( http . StatusNotFound )
return
}
}
2023-09-15 08:13:19 +02:00
if err := attach . IncreaseDownloadCount ( ctx ) ; err != nil {
2021-04-12 16:49:26 +02:00
ctx . ServerError ( "IncreaseDownloadCount" , err )
return
}
2024-05-30 15:33:50 +08:00
if setting . Attachment . Storage . ServeDirect ( ) {
2022-01-20 18:46:10 +01:00
// If we have a signed url (S3, object storage), redirect to this directly.
2024-10-31 23:28:25 +08:00
u , err := storage . Attachments . URL ( attach . RelativePath ( ) , attach . Name , nil )
2020-08-18 12:23:45 +08:00
if u != nil && err == nil {
ctx . Redirect ( u . String ( ) )
return
}
}
2021-04-12 16:49:26 +02:00
if httpcache . HandleGenericETagCache ( ctx . Req , ctx . Resp , ` " ` + attach . UUID + ` " ` ) {
return
}
2022-01-20 18:46:10 +01:00
// If we have matched and access to release or issue
2020-08-18 12:23:45 +08:00
fr , err := storage . Attachments . Open ( attach . RelativePath ( ) )
2020-01-05 00:20:08 +01:00
if err != nil {
ctx . ServerError ( "Open" , err )
return
}
defer fr . Close ( )
2023-07-07 07:31:56 +02:00
common . ServeContentByReadSeeker ( ctx . Base , attach . Name , util . ToPointer ( attach . CreatedUnix . AsTime ( ) ) , fr )
2020-01-05 00:20:08 +01:00
}
2023-04-12 11:05:23 +02:00
// GetAttachment serve attachments
func GetAttachment ( ctx * context . Context ) {
2024-06-19 06:32:45 +08:00
ServeAttachment ( ctx , ctx . PathParam ( ":uuid" ) )
2023-04-12 11:05:23 +02:00
}