From bae4c4381f622cd84cf4aa005b7d62cf10cec27f Mon Sep 17 00:00:00 2001 From: beer-psi Date: Fri, 31 Oct 2025 00:31:18 +0700 Subject: [PATCH 1/5] fix(share): slice content label by utf-8 runes --- core/share.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/share.go b/core/share.go index 202c27d89..530c6e324 100644 --- a/core/share.go +++ b/core/share.go @@ -4,6 +4,7 @@ import ( "context" "strings" "time" + "unicode/utf8" "github.com/Masterminds/squirrel" "github.com/deluan/rest" @@ -119,8 +120,9 @@ func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) { log.Error(r.ctx, "Invalid Resource ID", "id", firstId) return "", model.ErrNotFound } - if len(s.Contents) > 30 { - s.Contents = s.Contents[:26] + "..." + + if utf8.RuneCountInString(s.Contents) > 30 { + s.Contents = string([]rune(s.Contents)[:26]) + "..." } id, err = r.Persistable.Save(s) From 644792e18ad749273e10d52943eceb085a0c883a Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beer-psi@users.noreply.github.com> Date: Fri, 31 Oct 2025 00:47:33 +0700 Subject: [PATCH 2/5] Apply suggestions about avoiding allocations Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- core/share.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core/share.go b/core/share.go index 530c6e324..98a3ed3ca 100644 --- a/core/share.go +++ b/core/share.go @@ -121,8 +121,20 @@ func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) { return "", model.ErrNotFound } - if utf8.RuneCountInString(s.Contents) > 30 { - s.Contents = string([]rune(s.Contents)[:26]) + "..." + const maxContentRunes = 30 + const truncateToRunes = 26 + + var runeCount int + var truncateIndex int + for i := range s.Contents { + runeCount++ + if runeCount == truncateToRunes+1 { + truncateIndex = i + } + } + + if runeCount > maxContentRunes { + s.Contents = s.Contents[:truncateIndex] + "..." } id, err = r.Persistable.Save(s) From 3988733c3132ec5d2d582cc05c0fd2af10849022 Mon Sep 17 00:00:00 2001 From: beer-psi Date: Sun, 2 Nov 2025 09:15:04 +0700 Subject: [PATCH 3/5] lint: remove unused import --- core/share.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/core/share.go b/core/share.go index 530c6e324..c46b40a95 100644 --- a/core/share.go +++ b/core/share.go @@ -4,7 +4,6 @@ import ( "context" "strings" "time" - "unicode/utf8" "github.com/Masterminds/squirrel" "github.com/deluan/rest" @@ -121,8 +120,19 @@ func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) { return "", model.ErrNotFound } - if utf8.RuneCountInString(s.Contents) > 30 { - s.Contents = string([]rune(s.Contents)[:26]) + "..." + var runeCount int + var truncateIndex int + + for i := range s.Contents { + runeCount++ + + if runeCount == 27 { + truncateIndex = i + } + } + + if runeCount > 30 { + s.Contents = s.Contents[:truncateIndex] + "..." } id, err = r.Persistable.Save(s) From d7235f80a4fb52db82b75e6d1f9cc13aefb520a4 Mon Sep 17 00:00:00 2001 From: beer-psi Date: Sun, 2 Nov 2025 09:48:37 +0700 Subject: [PATCH 4/5] test: add test cases for CJK truncation --- core/share_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/share_test.go b/core/share_test.go index 21069bb59..d85c4c582 100644 --- a/core/share_test.go +++ b/core/share_test.go @@ -38,6 +38,22 @@ var _ = Describe("Share", func() { Expect(id).ToNot(BeEmpty()) Expect(entity.ID).To(Equal(id)) }) + + It("does not truncate CJK labels shorter than 30 runes", func() { + _ = ds.MediaFile(ctx).Put(&model.MediaFile{ID: "456", Title: "青春コンプレックス"}) + entity := &model.Share{Description: "test", ResourceIDs: "456"} + _, err := repo.Save(entity) + Expect(err).ToNot(HaveOccurred()) + Expect(entity.Contents).To(Equal("青春コンプレックス")) + }) + + It("truncates CJK labels longer than 30 runes", func() { + _ = ds.MediaFile(ctx).Put(&model.MediaFile{ID: "789", Title: "私の中の幻想的世界観及びその顕現を想起させたある現実での出来事に関する一考察"}) + entity := &model.Share{Description: "test", ResourceIDs: "789"} + _, err := repo.Save(entity) + Expect(err).ToNot(HaveOccurred()) + Expect(entity.Contents).To(Equal("私の中の幻想的世界観及びその顕現を想起させたある現実...")) + }) }) Describe("Update", func() { From 9b974e15537aecf5ae3c4f0498d289c166e92ef5 Mon Sep 17 00:00:00 2001 From: beer-psi Date: Sun, 2 Nov 2025 11:25:47 +0700 Subject: [PATCH 5/5] test: add tests for ASCII labels too --- core/share_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/share_test.go b/core/share_test.go index d85c4c582..ad5a986b1 100644 --- a/core/share_test.go +++ b/core/share_test.go @@ -39,6 +39,22 @@ var _ = Describe("Share", func() { Expect(entity.ID).To(Equal(id)) }) + It("does not truncate ASCII labels shorter than 30 characters", func() { + _ = ds.MediaFile(ctx).Put(&model.MediaFile{ID: "456", Title: "Example Media File"}) + entity := &model.Share{Description: "test", ResourceIDs: "456"} + _, err := repo.Save(entity) + Expect(err).ToNot(HaveOccurred()) + Expect(entity.Contents).To(Equal("Example Media File")) + }) + + It("truncates ASCII labels longer than 30 characters", func() { + _ = ds.MediaFile(ctx).Put(&model.MediaFile{ID: "789", Title: "Example Media File But The Title Is Really Long For Testing Purposes"}) + entity := &model.Share{Description: "test", ResourceIDs: "789"} + _, err := repo.Save(entity) + Expect(err).ToNot(HaveOccurred()) + Expect(entity.Contents).To(Equal("Example Media File But The...")) + }) + It("does not truncate CJK labels shorter than 30 runes", func() { _ = ds.MediaFile(ctx).Put(&model.MediaFile{ID: "456", Title: "青春コンプレックス"}) entity := &model.Share{Description: "test", ResourceIDs: "456"}