From 3c8a87ca14e866c10d535da3497be2a1b50bd48c Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Tue, 23 Sep 2025 10:39:58 +0000 Subject: [PATCH] appview/models: move db.String into models Signed-off-by: oppiliappan --- appview/ingester.go | 4 ++-- appview/db/strings.go | 115 +++++-------------------------------------------------------------------------------------------------------------- appview/models/string.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/notify/merged_notifier.go | 5 ++--- appview/notify/notifier.go | 9 ++++----- appview/pages/pages.go | 12 ++++++------ appview/posthog/notifier.go | 5 ++--- appview/strings/strings.go | 5 +++-- appview/validator/string.go | 27 +++++++++++++++++++++++++++ 9 file(s) changed, 146 insertion(s)(+), 131 deletion(s)(-) diff --git a/appview/ingester.go b/appview/ingester.go --- a/appview/ingester.go +++ b/appview/ingester.go @@ -594,9 +594,9 @@ return err } - string := db.StringFromRecord(did, rkey, record) + string := models.StringFromRecord(did, rkey, record) - if err = string.Validate(); err != nil { + if err = i.Validator.ValidateString(&string); err != nil { l.Error("invalid record", "err", err) return err } diff --git a/appview/db/strings.go b/appview/db/strings.go --- a/appview/db/strings.go +++ b/appview/db/strings.go @@ -1,95 +1,16 @@ package db import ( - "bytes" "database/sql" "errors" "fmt" - "io" "strings" "time" - "unicode/utf8" - "github.com/bluesky-social/indigo/atproto/syntax" - "tangled.org/core/api/tangled" + "tangled.org/core/appview/models" ) -type String struct { - Did syntax.DID - Rkey string - - Filename string - Description string - Contents string - Created time.Time - Edited *time.Time -} - -func (s *String) StringAt() syntax.ATURI { - return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", s.Did, tangled.StringNSID, s.Rkey)) -} - -type StringStats struct { - LineCount uint64 - ByteCount uint64 -} - -func (s String) Stats() StringStats { - lineCount, err := countLines(strings.NewReader(s.Contents)) - if err != nil { - // non-fatal - // TODO: log this? - } - - return StringStats{ - LineCount: uint64(lineCount), - ByteCount: uint64(len(s.Contents)), - } -} - -func (s String) Validate() error { - var err error - - if utf8.RuneCountInString(s.Filename) > 140 { - err = errors.Join(err, fmt.Errorf("filename too long")) - } - - if utf8.RuneCountInString(s.Description) > 280 { - err = errors.Join(err, fmt.Errorf("description too long")) - } - - if len(s.Contents) == 0 { - err = errors.Join(err, fmt.Errorf("contents is empty")) - } - - return err -} - -func (s *String) AsRecord() tangled.String { - return tangled.String{ - Filename: s.Filename, - Description: s.Description, - Contents: s.Contents, - CreatedAt: s.Created.Format(time.RFC3339), - } -} - -func StringFromRecord(did, rkey string, record tangled.String) String { - created, err := time.Parse(record.CreatedAt, time.RFC3339) - if err != nil { - created = time.Now() - } - return String{ - Did: syntax.DID(did), - Rkey: rkey, - Filename: record.Filename, - Description: record.Description, - Contents: record.Contents, - Created: created, - } -} - -func AddString(e Execer, s String) error { +func AddString(e Execer, s models.String) error { _, err := e.Exec( `insert into strings ( did, @@ -123,8 +44,8 @@ return err } -func GetStrings(e Execer, limit int, filters ...filter) ([]String, error) { - var all []String +func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) { + var all []models.String var conditions []string var args []any @@ -167,7 +88,7 @@ defer rows.Close() for rows.Next() { - var s String + var s models.String var createdAt string var editedAt sql.NullString @@ -247,30 +168,4 @@ _, err := e.Exec(query, args...) return err -} - -func countLines(r io.Reader) (int, error) { - buf := make([]byte, 32*1024) - bufLen := 0 - count := 0 - nl := []byte{'\n'} - - for { - c, err := r.Read(buf) - if c > 0 { - bufLen += c - } - count += bytes.Count(buf[:c], nl) - - switch { - case err == io.EOF: - /* handle last line not having a newline at the end */ - if bufLen >= 1 && buf[(bufLen-1)%(32*1024)] != '\n' { - count++ - } - return count, nil - case err != nil: - return 0, err - } - } } diff --git a/appview/models/string.go b/appview/models/string.go new file mode 100644 --- /dev/null +++ b/appview/models/string.go @@ -0,0 +1,95 @@ +package models + +import ( + "bytes" + "fmt" + "io" + "strings" + "time" + + "github.com/bluesky-social/indigo/atproto/syntax" + "tangled.org/core/api/tangled" +) + +type String struct { + Did syntax.DID + Rkey string + + Filename string + Description string + Contents string + Created time.Time + Edited *time.Time +} + +func (s *String) StringAt() syntax.ATURI { + return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", s.Did, tangled.StringNSID, s.Rkey)) +} + +func (s *String) AsRecord() tangled.String { + return tangled.String{ + Filename: s.Filename, + Description: s.Description, + Contents: s.Contents, + CreatedAt: s.Created.Format(time.RFC3339), + } +} + +func StringFromRecord(did, rkey string, record tangled.String) String { + created, err := time.Parse(record.CreatedAt, time.RFC3339) + if err != nil { + created = time.Now() + } + return String{ + Did: syntax.DID(did), + Rkey: rkey, + Filename: record.Filename, + Description: record.Description, + Contents: record.Contents, + Created: created, + } +} + +type StringStats struct { + LineCount uint64 + ByteCount uint64 +} + +func (s String) Stats() StringStats { + lineCount, err := countLines(strings.NewReader(s.Contents)) + if err != nil { + // non-fatal + // TODO: log this? + } + + return StringStats{ + LineCount: uint64(lineCount), + ByteCount: uint64(len(s.Contents)), + } +} + +func countLines(r io.Reader) (int, error) { + buf := make([]byte, 32*1024) + bufLen := 0 + count := 0 + nl := []byte{'\n'} + + for { + c, err := r.Read(buf) + if c > 0 { + bufLen += c + } + count += bytes.Count(buf[:c], nl) + + switch { + case err == io.EOF: + /* handle last line not having a newline at the end */ + if bufLen >= 1 && buf[(bufLen-1)%(32*1024)] != '\n' { + count++ + } + return count, nil + case err != nil: + return 0, err + } + } +} diff --git a/appview/notify/merged_notifier.go b/appview/notify/merged_notifier.go --- a/appview/notify/merged_notifier.go +++ b/appview/notify/merged_notifier.go @@ -3,7 +3,6 @@ import ( "context" - "tangled.org/core/appview/db" "tangled.org/core/appview/models" ) @@ -68,13 +67,13 @@ } } -func (m *mergedNotifier) NewString(ctx context.Context, string *db.String) { +func (m *mergedNotifier) NewString(ctx context.Context, string *models.String) { for _, notifier := range m.notifiers { notifier.NewString(ctx, string) } } -func (m *mergedNotifier) EditString(ctx context.Context, string *db.String) { +func (m *mergedNotifier) EditString(ctx context.Context, string *models.String) { for _, notifier := range m.notifiers { notifier.EditString(ctx, string) } diff --git a/appview/notify/notifier.go b/appview/notify/notifier.go --- a/appview/notify/notifier.go +++ b/appview/notify/notifier.go @@ -3,7 +3,6 @@ import ( "context" - "tangled.org/core/appview/db" "tangled.org/core/appview/models" ) @@ -23,8 +22,8 @@ UpdateProfile(ctx context.Context, profile *models.Profile) - NewString(ctx context.Context, s *db.String) - EditString(ctx context.Context, s *db.String) + NewString(ctx context.Context, s *models.String) + EditString(ctx context.Context, s *models.String) DeleteString(ctx context.Context, did, rkey string) } @@ -48,6 +47,6 @@ func (m *BaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {} -func (m *BaseNotifier) NewString(ctx context.Context, s *db.String) {} -func (m *BaseNotifier) EditString(ctx context.Context, s *db.String) {} +func (m *BaseNotifier) NewString(ctx context.Context, s *models.String) {} +func (m *BaseNotifier) EditString(ctx context.Context, s *models.String) {} func (m *BaseNotifier) DeleteString(ctx context.Context, did, rkey string) {} diff --git a/appview/pages/pages.go b/appview/pages/pages.go --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -477,7 +477,7 @@ type ProfileStringsParams struct { LoggedInUser *oauth.User - Strings []db.String + Strings []models.String Card *ProfileCard Active string } @@ -1308,7 +1308,7 @@ Action string // this is supplied in the case of editing an existing string - String db.String + String models.String } func (p *Pages) PutString(w io.Writer, params PutStringParams) error { @@ -1318,7 +1318,7 @@ type StringsDashboardParams struct { LoggedInUser *oauth.User Card ProfileCard - Strings []db.String + Strings []models.String } func (p *Pages) StringsDashboard(w io.Writer, params StringsDashboardParams) error { @@ -1327,7 +1327,7 @@ type StringTimelineParams struct { LoggedInUser *oauth.User - Strings []db.String + Strings []models.String } func (p *Pages) StringsTimeline(w io.Writer, params StringTimelineParams) error { @@ -1339,8 +1339,8 @@ ShowRendered bool RenderToggle bool RenderedContents template.HTML - String db.String - Stats db.StringStats + String models.String + Stats models.StringStats Owner identity.Identity } diff --git a/appview/posthog/notifier.go b/appview/posthog/notifier.go --- a/appview/posthog/notifier.go +++ b/appview/posthog/notifier.go @@ -5,7 +5,6 @@ "log" "github.com/posthog/posthog-go" - "tangled.org/core/appview/db" "tangled.org/core/appview/models" "tangled.org/core/appview/notify" ) @@ -142,7 +141,7 @@ } } -func (n *posthogNotifier) EditString(ctx context.Context, string *db.String) { +func (n *posthogNotifier) EditString(ctx context.Context, string *models.String) { err := n.client.Enqueue(posthog.Capture{ DistinctId: string.Did.String(), Event: "edit_string", @@ -153,7 +152,7 @@ } } -func (n *posthogNotifier) CreateString(ctx context.Context, string *db.String) { +func (n *posthogNotifier) CreateString(ctx context.Context, string models.String) { err := n.client.Enqueue(posthog.Capture{ DistinctId: string.Did.String(), Event: "create_string", diff --git a/appview/strings/strings.go b/appview/strings/strings.go --- a/appview/strings/strings.go +++ b/appview/strings/strings.go @@ -11,6 +11,7 @@ "tangled.org/core/api/tangled" "tangled.org/core/appview/db" "tangled.org/core/appview/middleware" + "tangled.org/core/appview/models" "tangled.org/core/appview/notify" "tangled.org/core/appview/oauth" "tangled.org/core/appview/pages" @@ -235,7 +236,7 @@ description := r.FormValue("description") // construct new string from form values - entry := db.String{ + entry := models.String{ Did: first.Did, Rkey: first.Rkey, Filename: filename, @@ -318,7 +319,7 @@ description := r.FormValue("description") - string := db.String{ + string := models.String{ Did: syntax.DID(user.Did), Rkey: tid.TID(), Filename: filename, diff --git a/appview/validator/string.go b/appview/validator/string.go new file mode 100644 --- /dev/null +++ b/appview/validator/string.go @@ -0,0 +1,27 @@ +package validator + +import ( + "errors" + "fmt" + "unicode/utf8" + + "tangled.org/core/appview/models" +) + +func (v *Validator) ValidateString(s *models.String) error { + var err error + + if utf8.RuneCountInString(s.Filename) > 140 { + err = errors.Join(err, fmt.Errorf("filename too long")) + } + + if utf8.RuneCountInString(s.Description) > 280 { + err = errors.Join(err, fmt.Errorf("description too long")) + } + + if len(s.Contents) == 0 { + err = errors.Join(err, fmt.Errorf("contents is empty")) + } + + return err +} -- tangled.sh