@@ -18,18 +18,22 @@ import (
18
18
19
19
// Attachment represent a attachment of issue/comment/release.
20
20
type Attachment struct {
21
- ID int64 `xorm:"pk autoincr"`
22
- UUID string `xorm:"uuid UNIQUE"`
23
- RepoID int64 `xorm:"INDEX"` // this should not be zero
24
- IssueID int64 `xorm:"INDEX"` // maybe zero when creating
25
- ReleaseID int64 `xorm:"INDEX"` // maybe zero when creating
26
- UploaderID int64 `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
27
- CommentID int64 `xorm:"INDEX"`
28
- Name string
29
- DownloadCount int64 `xorm:"DEFAULT 0"`
30
- Size int64 `xorm:"DEFAULT 0"`
31
- CreatedUnix timeutil.TimeStamp `xorm:"created"`
32
- CustomDownloadURL string `xorm:"-"`
21
+ ID int64 `xorm:"pk autoincr"`
22
+ UUID string `xorm:"uuid UNIQUE"`
23
+ RepoID int64 `xorm:"INDEX"` // this should not be zero
24
+ IssueID int64 `xorm:"INDEX"` // maybe zero when creating
25
+ ReleaseID int64 `xorm:"INDEX"` // maybe zero when creating
26
+ UploaderID int64 `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added
27
+ CommentID int64 `xorm:"INDEX"`
28
+ Name string
29
+ DownloadCount int64 `xorm:"DEFAULT 0"`
30
+ Status db.FileStatus `xorm:"INDEX DEFAULT 0"`
31
+ DeleteFailedCount int `xorm:"DEFAULT 0"` // Number of times the deletion failed, used to prevent infinite loop
32
+ LastDeleteFailedReason string `xorm:"TEXT"` // Last reason the deletion failed, used to prevent infinite loop
33
+ LastDeleteFailedTime timeutil.TimeStamp // Last time the deletion failed, used to prevent infinite loop
34
+ Size int64 `xorm:"DEFAULT 0"`
35
+ CreatedUnix timeutil.TimeStamp `xorm:"created"`
36
+ CustomDownloadURL string `xorm:"-"`
33
37
}
34
38
35
39
func init () {
@@ -88,7 +92,9 @@ func (err ErrAttachmentNotExist) Unwrap() error {
88
92
// GetAttachmentByID returns attachment by given id
89
93
func GetAttachmentByID (ctx context.Context , id int64 ) (* Attachment , error ) {
90
94
attach := & Attachment {}
91
- if has , err := db .GetEngine (ctx ).ID (id ).Get (attach ); err != nil {
95
+ if has , err := db .GetEngine (ctx ).ID (id ).
96
+ And ("status = ?" , db .FileStatusNormal ).
97
+ Get (attach ); err != nil {
92
98
return nil , err
93
99
} else if ! has {
94
100
return nil , ErrAttachmentNotExist {ID : id , UUID : "" }
@@ -99,7 +105,9 @@ func GetAttachmentByID(ctx context.Context, id int64) (*Attachment, error) {
99
105
// GetAttachmentByUUID returns attachment by given UUID.
100
106
func GetAttachmentByUUID (ctx context.Context , uuid string ) (* Attachment , error ) {
101
107
attach := & Attachment {}
102
- has , err := db .GetEngine (ctx ).Where ("uuid=?" , uuid ).Get (attach )
108
+ has , err := db .GetEngine (ctx ).Where ("uuid=?" , uuid ).
109
+ And ("status = ?" , db .FileStatusNormal ).
110
+ Get (attach )
103
111
if err != nil {
104
112
return nil , err
105
113
} else if ! has {
@@ -116,18 +124,24 @@ func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment,
116
124
117
125
// Silently drop invalid uuids.
118
126
attachments := make ([]* Attachment , 0 , len (uuids ))
119
- return attachments , db .GetEngine (ctx ).In ("uuid" , uuids ).Find (& attachments )
127
+ return attachments , db .GetEngine (ctx ).In ("uuid" , uuids ).
128
+ And ("status = ?" , db .FileStatusNormal ).
129
+ Find (& attachments )
120
130
}
121
131
122
132
// ExistAttachmentsByUUID returns true if attachment exists with the given UUID
123
133
func ExistAttachmentsByUUID (ctx context.Context , uuid string ) (bool , error ) {
124
- return db .GetEngine (ctx ).Where ("`uuid`=?" , uuid ).Exist (new (Attachment ))
134
+ return db .GetEngine (ctx ).Where ("`uuid`=?" , uuid ).
135
+ And ("status = ?" , db .FileStatusNormal ).
136
+ Exist (new (Attachment ))
125
137
}
126
138
127
139
// GetAttachmentsByIssueID returns all attachments of an issue.
128
140
func GetAttachmentsByIssueID (ctx context.Context , issueID int64 ) ([]* Attachment , error ) {
129
141
attachments := make ([]* Attachment , 0 , 10 )
130
- return attachments , db .GetEngine (ctx ).Where ("issue_id = ? AND comment_id = 0" , issueID ).Find (& attachments )
142
+ return attachments , db .GetEngine (ctx ).Where ("issue_id = ? AND comment_id = 0" , issueID ).
143
+ And ("status = ?" , db .FileStatusNormal ).
144
+ Find (& attachments )
131
145
}
132
146
133
147
// GetAttachmentsByIssueIDImagesLatest returns the latest image attachments of an issue.
@@ -142,19 +156,23 @@ func GetAttachmentsByIssueIDImagesLatest(ctx context.Context, issueID int64) ([]
142
156
OR name like '%.jxl'
143
157
OR name like '%.png'
144
158
OR name like '%.svg'
145
- OR name like '%.webp')` , issueID ).Desc ("comment_id" ).Limit (5 ).Find (& attachments )
159
+ OR name like '%.webp')` , issueID ).
160
+ And ("status = ?" , db .FileStatusNormal ).
161
+ Desc ("comment_id" ).Limit (5 ).Find (& attachments )
146
162
}
147
163
148
164
// GetAttachmentsByCommentID returns all attachments if comment by given ID.
149
165
func GetAttachmentsByCommentID (ctx context.Context , commentID int64 ) ([]* Attachment , error ) {
150
166
attachments := make ([]* Attachment , 0 , 10 )
151
- return attachments , db .GetEngine (ctx ).Where ("comment_id=?" , commentID ).Find (& attachments )
167
+ return attachments , db .GetEngine (ctx ).Where ("comment_id=?" , commentID ).
168
+ And ("status = ?" , db .FileStatusNormal ).
169
+ Find (& attachments )
152
170
}
153
171
154
172
// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName.
155
173
func GetAttachmentByReleaseIDFileName (ctx context.Context , releaseID int64 , fileName string ) (* Attachment , error ) {
156
174
attach := & Attachment {ReleaseID : releaseID , Name : fileName }
157
- has , err := db .GetEngine (ctx ).Get (attach )
175
+ has , err := db .GetEngine (ctx ).Where ( "status = ?" , db . FileStatusNormal ). Get (attach )
158
176
if err != nil {
159
177
return nil , err
160
178
} else if ! has {
@@ -185,7 +203,8 @@ func UpdateAttachment(ctx context.Context, atta *Attachment) error {
185
203
return err
186
204
}
187
205
188
- func DeleteAttachments (ctx context.Context , attachments []* Attachment ) (int64 , error ) {
206
+ // MarkAttachmentsDeleted marks the given attachments as deleted
207
+ func MarkAttachmentsDeleted (ctx context.Context , attachments []* Attachment ) (int64 , error ) {
189
208
if len (attachments ) == 0 {
190
209
return 0 , nil
191
210
}
@@ -195,15 +214,41 @@ func DeleteAttachments(ctx context.Context, attachments []*Attachment) (int64, e
195
214
ids = append (ids , a .ID )
196
215
}
197
216
198
- return db .GetEngine (ctx ).In ("id" , ids ).NoAutoCondition ().Delete (attachments [0 ])
217
+ return db .GetEngine (ctx ).Table ("attachment" ).In ("id" , ids ).Update (map [string ]any {
218
+ "status" : db .FileStatusToBeDeleted ,
219
+ })
199
220
}
200
221
201
- // DeleteAttachmentsByRelease deletes all attachments associated with the given release.
202
- func DeleteAttachmentsByRelease (ctx context.Context , releaseID int64 ) error {
203
- _ , err := db .GetEngine (ctx ).Where ("release_id = ?" , releaseID ).Delete (& Attachment {})
222
+ // MarkAttachmentsDeletedByRelease marks all attachments associated with the given release as deleted.
223
+ func MarkAttachmentsDeletedByRelease (ctx context.Context , releaseID int64 ) error {
224
+ _ , err := db .GetEngine (ctx ).Table ("attachment" ).Where ("release_id = ?" , releaseID ).Update (map [string ]any {
225
+ "status" : db .FileStatusToBeDeleted ,
226
+ })
204
227
return err
205
228
}
206
229
230
+ // DeleteAttachmentByID deletes the attachment which has been marked as deleted by given id
231
+ func DeleteAttachmentByID (ctx context.Context , id int64 ) error {
232
+ cnt , err := db .GetEngine (ctx ).ID (id ).Where ("status = ?" , db .FileStatusToBeDeleted ).Delete (new (Attachment ))
233
+ if err != nil {
234
+ return fmt .Errorf ("delete attachment by id: %w" , err )
235
+ }
236
+ if cnt != 1 {
237
+ return fmt .Errorf ("the attachment with id %d was not found or is not marked for deletion" , id )
238
+ }
239
+ return nil
240
+ }
241
+
242
+ func UpdateAttachmentFailure (ctx context.Context , attachment * Attachment , err error ) error {
243
+ attachment .DeleteFailedCount ++
244
+ _ , updateErr := db .GetEngine (ctx ).Table ("attachment" ).ID (attachment .ID ).Update (map [string ]any {
245
+ "delete_failed_count" : attachment .DeleteFailedCount ,
246
+ "last_delete_failed_reason" : err .Error (),
247
+ "last_delete_failed_time" : timeutil .TimeStampNow (),
248
+ })
249
+ return updateErr
250
+ }
251
+
207
252
// CountOrphanedAttachments returns the number of bad attachments
208
253
func CountOrphanedAttachments (ctx context.Context ) (int64 , error ) {
209
254
return db .GetEngine (ctx ).Where ("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))" ).
0 commit comments