UploadAndAttach uploads assets in order and stops at the first failure. It points existing references at the URLs of successful uploads and appends only successful uploads the markdown did not reference. Assets after a failure are not attempted. The result reports how many assets reached the server
(ctx context.Context, md string, assets []UserAsset)
| 28 | // The markdown is returned unchanged when it could not be rewritten, so a |
| 29 | // caller that assigns the result in place never destroys what it was given. |
| 30 | func (u *Uploader) UploadAndAttach(ctx context.Context, md string, assets []UserAsset) (string, UploadResult, error) { |
| 31 | args := make([]attachmentArg, len(assets)) |
| 32 | for i, a := range assets { |
| 33 | f := a.getAsset() |
| 34 | args[i] = attachmentArg{Path: f.path, Alt: f.alt, RendersAsPlayer: a.rendersAsPlayer()} |
| 35 | } |
| 36 | |
| 37 | attachableMD, err := newAttachableMarkdown(md, args) |
| 38 | if err != nil { |
| 39 | return md, UploadResult{}, err |
| 40 | } |
| 41 | |
| 42 | var failures []error |
| 43 | result := UploadResult{} |
| 44 | for i, a := range assets { |
| 45 | assetURL, err := u.upload(ctx, a) |
| 46 | if err != nil { |
| 47 | // Stopping at the first failure. It makes recovery much simpler. |
| 48 | failures = append(failures, err) |
| 49 | break |
| 50 | } |
| 51 | args[i].URL = assetURL |
| 52 | result.Uploaded++ |
| 53 | } |
| 54 | |
| 55 | attachedMD, err := attachAssetsToMarkdown(attachableMD) |
| 56 | if err != nil { |
| 57 | failures = append(failures, err) |
| 58 | return md, result, errors.Join(failures...) |
| 59 | } |
| 60 | |
| 61 | result.AppendOperations = len(attachedMD.ToAppend) |
| 62 | result.ReplaceOperations = attachedMD.ReplaceOperations |
| 63 | return appendUnreferenced(attachedMD, assets), result, errors.Join(failures...) |
| 64 | } |
| 65 | |
| 66 | // appendUnreferenced adds a paragraph for every attachment the author never |
| 67 | // referenced, in the order they were attached. Each one renders itself, since |