mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-01-31 04:02:24 +00:00
[bugfix] don't return error during account serialize on deleted emoji (#1177)
* only return error for emoji fetch if NOT errnoentries Signed-off-by: kim <grufwub@gmail.com> * reformat gts->api model slice conversion to standard error behaviours and reduce code reuse Signed-off-by: kim <grufwub@gmail.com> Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
d445c60a26
commit
cfa8d7900c
|
@ -82,10 +82,6 @@ func (c *converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.Account) (*model.Account, error) {
|
func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.Account) (*model.Account, error) {
|
||||||
if a == nil {
|
|
||||||
return nil, fmt.Errorf("given account was nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
// count followers
|
// count followers
|
||||||
followersCount, err := c.db.CountAccountFollowedBy(ctx, a.ID, false)
|
followersCount, err := c.db.CountAccountFollowedBy(ctx, a.ID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,11 +114,10 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
if a.AvatarMediaAttachmentID != "" {
|
if a.AvatarMediaAttachmentID != "" {
|
||||||
if a.AvatarMediaAttachment == nil {
|
if a.AvatarMediaAttachment == nil {
|
||||||
avi, err := c.db.GetAttachmentByID(ctx, a.AvatarMediaAttachmentID)
|
avi, err := c.db.GetAttachmentByID(ctx, a.AvatarMediaAttachmentID)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
a.AvatarMediaAttachment = avi
|
|
||||||
} else {
|
|
||||||
log.Errorf("AccountToAPIAccountPublic: error getting Avatar with id %s: %s", a.AvatarMediaAttachmentID, err)
|
log.Errorf("AccountToAPIAccountPublic: error getting Avatar with id %s: %s", a.AvatarMediaAttachmentID, err)
|
||||||
}
|
}
|
||||||
|
a.AvatarMediaAttachment = avi
|
||||||
}
|
}
|
||||||
if a.AvatarMediaAttachment != nil {
|
if a.AvatarMediaAttachment != nil {
|
||||||
aviURL = a.AvatarMediaAttachment.URL
|
aviURL = a.AvatarMediaAttachment.URL
|
||||||
|
@ -136,11 +131,10 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
if a.HeaderMediaAttachmentID != "" {
|
if a.HeaderMediaAttachmentID != "" {
|
||||||
if a.HeaderMediaAttachment == nil {
|
if a.HeaderMediaAttachment == nil {
|
||||||
avi, err := c.db.GetAttachmentByID(ctx, a.HeaderMediaAttachmentID)
|
avi, err := c.db.GetAttachmentByID(ctx, a.HeaderMediaAttachmentID)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
a.HeaderMediaAttachment = avi
|
|
||||||
} else {
|
|
||||||
log.Errorf("AccountToAPIAccountPublic: error getting Header with id %s: %s", a.HeaderMediaAttachmentID, err)
|
log.Errorf("AccountToAPIAccountPublic: error getting Header with id %s: %s", a.HeaderMediaAttachmentID, err)
|
||||||
}
|
}
|
||||||
|
a.HeaderMediaAttachment = avi
|
||||||
}
|
}
|
||||||
if a.HeaderMediaAttachment != nil {
|
if a.HeaderMediaAttachment != nil {
|
||||||
headerURL = a.HeaderMediaAttachment.URL
|
headerURL = a.HeaderMediaAttachment.URL
|
||||||
|
@ -148,41 +142,25 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the fields set on this account
|
// preallocate frontend fields slice
|
||||||
fields := []model.Field{}
|
fields := make([]model.Field, len(a.Fields))
|
||||||
for _, f := range a.Fields {
|
|
||||||
|
// Convert account GTS model fields to frontend
|
||||||
|
for i, field := range a.Fields {
|
||||||
mField := model.Field{
|
mField := model.Field{
|
||||||
Name: f.Name,
|
Name: field.Name,
|
||||||
Value: f.Value,
|
Value: field.Value,
|
||||||
}
|
}
|
||||||
if !f.VerifiedAt.IsZero() {
|
if !field.VerifiedAt.IsZero() {
|
||||||
mField.VerifiedAt = util.FormatISO8601(f.VerifiedAt)
|
mField.VerifiedAt = util.FormatISO8601(field.VerifiedAt)
|
||||||
}
|
}
|
||||||
fields = append(fields, mField)
|
fields[i] = mField
|
||||||
}
|
}
|
||||||
|
|
||||||
// account emojis
|
// convert account gts model emojis to frontend api model emojis
|
||||||
emojis := []model.Emoji{}
|
apiEmojis, err := c.convertEmojisToAPIEmojis(ctx, a.Emojis, a.EmojiIDs)
|
||||||
gtsEmojis := a.Emojis
|
|
||||||
if len(a.EmojiIDs) > len(gtsEmojis) {
|
|
||||||
gtsEmojis = []*gtsmodel.Emoji{}
|
|
||||||
for _, emojiID := range a.EmojiIDs {
|
|
||||||
emoji, err := c.db.GetEmojiByID(ctx, emojiID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("AccountToAPIAccountPublic: error getting emoji %s from database: %s", emojiID, err)
|
log.Errorf("error converting account emojis: %v", err)
|
||||||
}
|
|
||||||
gtsEmojis = append(gtsEmojis, emoji)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, emoji := range gtsEmojis {
|
|
||||||
if *emoji.Disabled {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiEmoji, err := c.EmojiToAPIEmoji(ctx, emoji)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("AccountToAPIAccountPublic: error converting emoji to api emoji: %s", err)
|
|
||||||
}
|
|
||||||
emojis = append(emojis, apiEmoji)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -234,7 +212,7 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
FollowingCount: followingCount,
|
FollowingCount: followingCount,
|
||||||
StatusesCount: statusesCount,
|
StatusesCount: statusesCount,
|
||||||
LastStatusAt: lastStatusAt,
|
LastStatusAt: lastStatusAt,
|
||||||
Emojis: emojis,
|
Emojis: apiEmojis,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
Suspended: suspended,
|
Suspended: suspended,
|
||||||
CustomCSS: a.CustomCSS,
|
CustomCSS: a.CustomCSS,
|
||||||
|
@ -497,130 +475,37 @@ func (c *converter) StatusToAPIStatus(ctx context.Context, s *gtsmodel.Status, r
|
||||||
return nil, fmt.Errorf("error parsing account of status author: %s", err)
|
return nil, fmt.Errorf("error parsing account of status author: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiAttachments := []model.Attachment{}
|
// convert status gts model attachments to frontend api model attachments
|
||||||
// the status might already have some gts attachments on it if it's not been pulled directly from the database
|
apiAttachments, err := c.convertAttachmentsToAPIAttachments(ctx, s.Attachments, s.AttachmentIDs)
|
||||||
// if so, we can directly convert the gts attachments into api ones
|
|
||||||
if s.Attachments != nil {
|
|
||||||
for _, gtsAttachment := range s.Attachments {
|
|
||||||
apiAttachment, err := c.AttachmentToAPIAttachment(ctx, gtsAttachment)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting attachment with id %s: %s", gtsAttachment.ID, err)
|
log.Errorf("error converting status attachments: %v", err)
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiAttachments = append(apiAttachments, apiAttachment)
|
|
||||||
}
|
|
||||||
// the status doesn't have gts attachments on it, but it does have attachment IDs
|
|
||||||
// in this case, we need to pull the gts attachments from the db to convert them into api ones
|
|
||||||
} else {
|
|
||||||
for _, aID := range s.AttachmentIDs {
|
|
||||||
gtsAttachment, err := c.db.GetAttachmentByID(ctx, aID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error getting attachment with id %s: %s", aID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiAttachment, err := c.AttachmentToAPIAttachment(ctx, gtsAttachment)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error converting attachment with id %s: %s", aID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiAttachments = append(apiAttachments, apiAttachment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apiMentions := []model.Mention{}
|
// convert status gts model mentions to frontend api model mentions
|
||||||
// the status might already have some gts mentions on it if it's not been pulled directly from the database
|
apiMentions, err := c.convertMentionsToAPIMentions(ctx, s.Mentions, s.MentionIDs)
|
||||||
// if so, we can directly convert the gts mentions into api ones
|
|
||||||
if s.Mentions != nil {
|
|
||||||
for _, gtsMention := range s.Mentions {
|
|
||||||
apiMention, err := c.MentionToAPIMention(ctx, gtsMention)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting mention with id %s: %s", gtsMention.ID, err)
|
log.Errorf("error converting status mentions: %v", err)
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiMentions = append(apiMentions, apiMention)
|
|
||||||
}
|
|
||||||
// the status doesn't have gts mentions on it, but it does have mention IDs
|
|
||||||
// in this case, we need to pull the gts mentions from the db to convert them into api ones
|
|
||||||
} else {
|
|
||||||
for _, mID := range s.MentionIDs {
|
|
||||||
gtsMention, err := c.db.GetMention(ctx, mID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error getting mention with id %s: %s", mID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiMention, err := c.MentionToAPIMention(ctx, gtsMention)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error converting mention with id %s: %s", gtsMention.ID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiMentions = append(apiMentions, apiMention)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apiTags := []model.Tag{}
|
// convert status gts model tags to frontend api model tags
|
||||||
// the status might already have some gts tags on it if it's not been pulled directly from the database
|
apiTags, err := c.convertTagsToAPITags(ctx, s.Tags, s.TagIDs)
|
||||||
// if so, we can directly convert the gts tags into api ones
|
|
||||||
if s.Tags != nil {
|
|
||||||
for _, gtsTag := range s.Tags {
|
|
||||||
apiTag, err := c.TagToAPITag(ctx, gtsTag)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting tag with id %s: %s", gtsTag.ID, err)
|
log.Errorf("error converting status tags: %v", err)
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiTags = append(apiTags, apiTag)
|
|
||||||
}
|
|
||||||
// the status doesn't have gts tags on it, but it does have tag IDs
|
|
||||||
// in this case, we need to pull the gts tags from the db to convert them into api ones
|
|
||||||
} else {
|
|
||||||
for _, t := range s.TagIDs {
|
|
||||||
gtsTag := >smodel.Tag{}
|
|
||||||
if err := c.db.GetByID(ctx, t, gtsTag); err != nil {
|
|
||||||
log.Errorf("error getting tag with id %s: %s", t, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiTag, err := c.TagToAPITag(ctx, gtsTag)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error converting tag with id %s: %s", gtsTag.ID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiTags = append(apiTags, apiTag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apiEmojis := []model.Emoji{}
|
// convert status gts model emojis to frontend api model emojis
|
||||||
// the status might already have some gts emojis on it if it's not been pulled directly from the database
|
apiEmojis, err := c.convertEmojisToAPIEmojis(ctx, s.Emojis, s.EmojiIDs)
|
||||||
// if so, we can directly convert the gts emojis into api ones
|
|
||||||
if s.Emojis != nil {
|
|
||||||
for _, gtsEmoji := range s.Emojis {
|
|
||||||
apiEmoji, err := c.EmojiToAPIEmoji(ctx, gtsEmoji)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err)
|
log.Errorf("error converting status emojis: %v", err)
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiEmojis = append(apiEmojis, apiEmoji)
|
|
||||||
}
|
|
||||||
// the status doesn't have gts emojis on it, but it does have emoji IDs
|
|
||||||
// in this case, we need to pull the gts emojis from the db to convert them into api ones
|
|
||||||
} else {
|
|
||||||
for _, e := range s.EmojiIDs {
|
|
||||||
gtsEmoji := >smodel.Emoji{}
|
|
||||||
if err := c.db.GetByID(ctx, e, gtsEmoji); err != nil {
|
|
||||||
log.Errorf("error getting emoji with id %s: %s", e, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiEmoji, err := c.EmojiToAPIEmoji(ctx, gtsEmoji)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
apiEmojis = append(apiEmojis, apiEmoji)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
statusInteractions := &statusInteractions{}
|
// Fetch status interaction flags for acccount
|
||||||
si, err := c.interactionsWithStatusForAccount(ctx, s, requestingAccount)
|
interacts, err := c.interactionsWithStatusForAccount(ctx, s, requestingAccount)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
statusInteractions = si
|
log.Errorf("error getting interactions for status %s for account %s: %v", s.ID, requestingAccount.ID, err)
|
||||||
|
|
||||||
|
// Ensure a non nil object
|
||||||
|
interacts = &statusInteractions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
apiStatus := &model.Status{
|
apiStatus := &model.Status{
|
||||||
|
@ -637,10 +522,10 @@ func (c *converter) StatusToAPIStatus(ctx context.Context, s *gtsmodel.Status, r
|
||||||
RepliesCount: repliesCount,
|
RepliesCount: repliesCount,
|
||||||
ReblogsCount: reblogsCount,
|
ReblogsCount: reblogsCount,
|
||||||
FavouritesCount: favesCount,
|
FavouritesCount: favesCount,
|
||||||
Favourited: statusInteractions.Faved,
|
Favourited: interacts.Faved,
|
||||||
Bookmarked: statusInteractions.Bookmarked,
|
Bookmarked: interacts.Bookmarked,
|
||||||
Muted: statusInteractions.Muted,
|
Muted: interacts.Muted,
|
||||||
Reblogged: statusInteractions.Reblogged,
|
Reblogged: interacts.Reblogged,
|
||||||
Pinned: *s.Pinned,
|
Pinned: *s.Pinned,
|
||||||
Content: s.Content,
|
Content: s.Content,
|
||||||
Reblog: nil,
|
Reblog: nil,
|
||||||
|
@ -896,3 +781,167 @@ func (c *converter) DomainBlockToAPIDomainBlock(ctx context.Context, b *gtsmodel
|
||||||
|
|
||||||
return domainBlock, nil
|
return domainBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertAttachmentsToAPIAttachments will convert a slice of GTS model attachments to frontend API model attachments, falling back to IDs if no GTS models supplied.
|
||||||
|
func (c *converter) convertAttachmentsToAPIAttachments(ctx context.Context, attachments []*gtsmodel.MediaAttachment, attachmentIDs []string) ([]model.Attachment, error) {
|
||||||
|
var errs multiError
|
||||||
|
|
||||||
|
if len(attachments) == 0 {
|
||||||
|
// GTS model attachments were not populated
|
||||||
|
|
||||||
|
// Preallocate expected GTS slice
|
||||||
|
attachments = make([]*gtsmodel.MediaAttachment, 0, len(attachmentIDs))
|
||||||
|
|
||||||
|
// Fetch GTS models for attachment IDs
|
||||||
|
for _, id := range attachmentIDs {
|
||||||
|
attachment, err := c.db.GetAttachmentByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error fetching attachment %s from database: %v", id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
attachments = append(attachments, attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate expected frontend slice
|
||||||
|
apiAttachments := make([]model.Attachment, 0, len(attachments))
|
||||||
|
|
||||||
|
// Convert GTS models to frontend models
|
||||||
|
for _, attachment := range attachments {
|
||||||
|
apiAttachment, err := c.AttachmentToAPIAttachment(ctx, attachment)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error converting attchment %s to api attachment: %v", attachment.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiAttachments = append(apiAttachments, apiAttachment)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiAttachments, errs.Combine()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertEmojisToAPIEmojis will convert a slice of GTS model emojis to frontend API model emojis, falling back to IDs if no GTS models supplied.
|
||||||
|
func (c *converter) convertEmojisToAPIEmojis(ctx context.Context, emojis []*gtsmodel.Emoji, emojiIDs []string) ([]model.Emoji, error) {
|
||||||
|
var errs multiError
|
||||||
|
|
||||||
|
if len(emojis) == 0 {
|
||||||
|
// GTS model attachments were not populated
|
||||||
|
|
||||||
|
// Preallocate expected GTS slice
|
||||||
|
emojis = make([]*gtsmodel.Emoji, 0, len(emojiIDs))
|
||||||
|
|
||||||
|
// Fetch GTS models for emoji IDs
|
||||||
|
for _, id := range emojiIDs {
|
||||||
|
emoji, err := c.db.GetEmojiByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error fetching emoji %s from database: %v", id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
emojis = append(emojis, emoji)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate expected frontend slice
|
||||||
|
apiEmojis := make([]model.Emoji, 0, len(emojis))
|
||||||
|
|
||||||
|
// Convert GTS models to frontend models
|
||||||
|
for _, emoji := range emojis {
|
||||||
|
apiEmoji, err := c.EmojiToAPIEmoji(ctx, emoji)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error converting emoji %s to api emoji: %v", emoji.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiEmojis = append(apiEmojis, apiEmoji)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiEmojis, errs.Combine()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertMentionsToAPIMentions will convert a slice of GTS model mentions to frontend API model mentions, falling back to IDs if no GTS models supplied.
|
||||||
|
func (c *converter) convertMentionsToAPIMentions(ctx context.Context, mentions []*gtsmodel.Mention, mentionIDs []string) ([]model.Mention, error) {
|
||||||
|
var errs multiError
|
||||||
|
|
||||||
|
if len(mentions) == 0 {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// GTS model mentions were not populated
|
||||||
|
//
|
||||||
|
// Fetch GTS models for mention IDs
|
||||||
|
mentions, err = c.db.GetMentions(ctx, mentionIDs)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error fetching mentions from database: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate expected frontend slice
|
||||||
|
apiMentions := make([]model.Mention, 0, len(mentions))
|
||||||
|
|
||||||
|
// Convert GTS models to frontend models
|
||||||
|
for _, mention := range mentions {
|
||||||
|
apiMention, err := c.MentionToAPIMention(ctx, mention)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error converting mention %s to api mention: %v", mention.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiMentions = append(apiMentions, apiMention)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiMentions, errs.Combine()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertTagsToAPITags will convert a slice of GTS model tags to frontend API model tags, falling back to IDs if no GTS models supplied.
|
||||||
|
func (c *converter) convertTagsToAPITags(ctx context.Context, tags []*gtsmodel.Tag, tagIDs []string) ([]model.Tag, error) {
|
||||||
|
var errs multiError
|
||||||
|
|
||||||
|
if len(tags) == 0 {
|
||||||
|
// GTS model tags were not populated
|
||||||
|
|
||||||
|
// Preallocate expected GTS slice
|
||||||
|
tags = make([]*gtsmodel.Tag, 0, len(tagIDs))
|
||||||
|
|
||||||
|
// Fetch GTS models for tag IDs
|
||||||
|
for _, id := range tagIDs {
|
||||||
|
tag := new(gtsmodel.Tag)
|
||||||
|
if err := c.db.GetByID(ctx, id, tag); err != nil {
|
||||||
|
errs.Appendf("error fetching tag %s from database: %v", id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate expected frontend slice
|
||||||
|
apiTags := make([]model.Tag, 0, len(tags))
|
||||||
|
|
||||||
|
// Convert GTS models to frontend models
|
||||||
|
for _, tag := range tags {
|
||||||
|
apiTag, err := c.TagToAPITag(ctx, tag)
|
||||||
|
if err != nil {
|
||||||
|
errs.Appendf("error converting tag %s to api tag: %v", tag.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apiTags = append(apiTags, apiTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiTags, errs.Combine()
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiError allows encapsulating multiple errors under a singular instance,
|
||||||
|
// which is useful when you only want to log on errors, not return early / bubble up.
|
||||||
|
// TODO: if this is useful elsewhere, move into a separate gts subpackage.
|
||||||
|
type multiError []string
|
||||||
|
|
||||||
|
func (e *multiError) Append(err error) {
|
||||||
|
*e = append(*e, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *multiError) Appendf(format string, args ...any) {
|
||||||
|
*e = append(*e, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine converts this multiError to a singular error instance, returning nil if empty.
|
||||||
|
func (e multiError) Combine() error {
|
||||||
|
if len(e) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(`"` + strings.Join(e, `","`) + `"`)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue