@@ -190,9 +190,13 @@ func DeleteIssue(ctx context.Context, doer *user_model.User, gitRepo *git.Reposi
190190 }
191191
192192 // delete entries in database
193- if err := deleteIssue (ctx , issue ); err != nil {
193+ attachmentPaths , err := deleteIssue (ctx , issue )
194+ if err != nil {
194195 return err
195196 }
197+ for _ , attachmentPath := range attachmentPaths {
198+ system_model .RemoveStorageWithNotice (ctx , storage .Attachments , "Delete issue attachment" , attachmentPath )
199+ }
196200
197201 // delete pull request related git data
198202 if issue .IsPull && gitRepo != nil {
@@ -256,45 +260,45 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i
256260}
257261
258262// 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 ) {
260264 ctx , committer , err := db .TxContext (ctx )
261265 if err != nil {
262- return err
266+ return nil , err
263267 }
264268 defer committer .Close ()
265269
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
269272 }
270273
271274 // update the total issue numbers
272275 if err := repo_model .UpdateRepoIssueNumbers (ctx , issue .RepoID , issue .IsPull , false ); err != nil {
273- return err
276+ return nil , err
274277 }
275278 // if the issue is closed, update the closed issue numbers
276279 if issue .IsClosed {
277280 if err := repo_model .UpdateRepoIssueNumbers (ctx , issue .RepoID , issue .IsPull , true ); err != nil {
278- return err
281+ return nil , err
279282 }
280283 }
281284
282285 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" ,
284287 issue .MilestoneID , err )
285288 }
286289
287290 if err := activities_model .DeleteIssueActions (ctx , issue .RepoID , issue .ID , issue .Index ); err != nil {
288- return err
291+ return nil , err
289292 }
290293
291294 // 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
294297 }
295298
299+ var attachmentPaths []string
296300 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 ())
298302 }
299303
300304 // delete all database data still assigned to this issue
@@ -318,8 +322,68 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error {
318322 & issues_model.Comment {DependentIssueID : issue .ID },
319323 & issues_model.IssuePin {IssueID : issue .ID },
320324 ); 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 {
321352 return err
322353 }
323354
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
325389}
0 commit comments