@@ -190,9 +190,13 @@ func DeleteIssue(ctx context.Context, doer *user_model.User, gitRepo *git.Reposi
190
190
}
191
191
192
192
// delete entries in database
193
- if err := deleteIssue (ctx , issue ); err != nil {
193
+ attachmentPaths , err := deleteIssue (ctx , issue )
194
+ if err != nil {
194
195
return err
195
196
}
197
+ for _ , attachmentPath := range attachmentPaths {
198
+ system_model .RemoveStorageWithNotice (ctx , storage .Attachments , "Delete issue attachment" , attachmentPath )
199
+ }
196
200
197
201
// delete pull request related git data
198
202
if issue .IsPull && gitRepo != nil {
@@ -256,45 +260,45 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i
256
260
}
257
261
258
262
// deleteIssue deletes the issue
259
- func deleteIssue (ctx context.Context , issue * issues_model.Issue ) error {
263
+ func deleteIssue (ctx context.Context , issue * issues_model.Issue ) ([] string , error ) {
260
264
ctx , committer , err := db .TxContext (ctx )
261
265
if err != nil {
262
- return err
266
+ return nil , err
263
267
}
264
268
defer committer .Close ()
265
269
266
- e := db .GetEngine (ctx )
267
- if _ , err := e .ID (issue .ID ).NoAutoCondition ().Delete (issue ); err != nil {
268
- return err
270
+ if _ , err := db .GetEngine (ctx ).ID (issue .ID ).NoAutoCondition ().Delete (issue ); err != nil {
271
+ return nil , err
269
272
}
270
273
271
274
// update the total issue numbers
272
275
if err := repo_model .UpdateRepoIssueNumbers (ctx , issue .RepoID , issue .IsPull , false ); err != nil {
273
- return err
276
+ return nil , err
274
277
}
275
278
// if the issue is closed, update the closed issue numbers
276
279
if issue .IsClosed {
277
280
if err := repo_model .UpdateRepoIssueNumbers (ctx , issue .RepoID , issue .IsPull , true ); err != nil {
278
- return err
281
+ return nil , err
279
282
}
280
283
}
281
284
282
285
if err := issues_model .UpdateMilestoneCounters (ctx , issue .MilestoneID ); err != nil {
283
- return fmt .Errorf ("error updating counters for milestone id %d: %w" ,
286
+ return nil , fmt .Errorf ("error updating counters for milestone id %d: %w" ,
284
287
issue .MilestoneID , err )
285
288
}
286
289
287
290
if err := activities_model .DeleteIssueActions (ctx , issue .RepoID , issue .ID , issue .Index ); err != nil {
288
- return err
291
+ return nil , err
289
292
}
290
293
291
294
// find attachments related to this issue and remove them
292
- if err := issue .LoadAttributes (ctx ); err != nil {
293
- return err
295
+ if err := issue .LoadAttachments (ctx ); err != nil {
296
+ return nil , err
294
297
}
295
298
299
+ var attachmentPaths []string
296
300
for i := range issue .Attachments {
297
- system_model . RemoveStorageWithNotice ( ctx , storage . Attachments , "Delete issue attachment" , issue .Attachments [i ].RelativePath ())
301
+ attachmentPaths = append ( attachmentPaths , issue .Attachments [i ].RelativePath ())
298
302
}
299
303
300
304
// delete all database data still assigned to this issue
@@ -318,8 +322,68 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error {
318
322
& issues_model.Comment {DependentIssueID : issue .ID },
319
323
& issues_model.IssuePin {IssueID : issue .ID },
320
324
); err != nil {
325
+ return nil , err
326
+ }
327
+
328
+ if err := committer .Commit (); err != nil {
329
+ return nil , err
330
+ }
331
+ return attachmentPaths , nil
332
+ }
333
+
334
+ // DeleteOrphanedIssues delete issues without a repo
335
+ func DeleteOrphanedIssues (ctx context.Context ) error {
336
+ var attachmentPaths []string
337
+ err := db .WithTx (ctx , func (ctx context.Context ) error {
338
+ repoIDs , err := issues_model .GetOrphanedIssueRepoIDs (ctx )
339
+ if err != nil {
340
+ return err
341
+ }
342
+ for i := range repoIDs {
343
+ paths , err := DeleteIssuesByRepoID (ctx , repoIDs [i ])
344
+ if err != nil {
345
+ return err
346
+ }
347
+ attachmentPaths = append (attachmentPaths , paths ... )
348
+ }
349
+ return nil
350
+ })
351
+ if err != nil {
321
352
return err
322
353
}
323
354
324
- return committer .Commit ()
355
+ // Remove issue attachment files.
356
+ for i := range attachmentPaths {
357
+ system_model .RemoveStorageWithNotice (ctx , storage .Attachments , "Delete issue attachment" , attachmentPaths [i ])
358
+ }
359
+ return nil
360
+ }
361
+
362
+ // DeleteIssuesByRepoID deletes issues by repositories id
363
+ func DeleteIssuesByRepoID (ctx context.Context , repoID int64 ) (attachmentPaths []string , err error ) {
364
+ for {
365
+ issues := make ([]* issues_model.Issue , 0 , db .DefaultMaxInSize )
366
+ if err := db .GetEngine (ctx ).
367
+ Where ("repo_id = ?" , repoID ).
368
+ OrderBy ("id" ).
369
+ Limit (db .DefaultMaxInSize ).
370
+ Find (& issues ); err != nil {
371
+ return nil , err
372
+ }
373
+
374
+ if len (issues ) == 0 {
375
+ break
376
+ }
377
+
378
+ for _ , issue := range issues {
379
+ issueAttachPaths , err := deleteIssue (ctx , issue )
380
+ if err != nil {
381
+ return nil , fmt .Errorf ("deleteIssue [issue_id: %d]: %w" , issue .ID , err )
382
+ }
383
+
384
+ attachmentPaths = append (attachmentPaths , issueAttachPaths ... )
385
+ }
386
+ }
387
+
388
+ return attachmentPaths , err
325
389
}
0 commit comments