forked from tangled.org/core
this repo has no description

appview/models: move db.String into models

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 3c8a87ca c07ba238

verified
Changed files
+146 -131
appview
+5 -110
appview/db/strings.go
···
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"
)
-
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 {
_, err := e.Exec(
`insert into strings (
did,
···
return err
}
-
func GetStrings(e Execer, limit int, filters ...filter) ([]String, error) {
-
var all []String
var conditions []string
var args []any
···
defer rows.Close()
for rows.Next() {
-
var s String
var createdAt string
var editedAt sql.NullString
···
_, 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
-
}
-
}
-
}
···
package db
import (
"database/sql"
"errors"
"fmt"
"strings"
"time"
+
"tangled.org/core/appview/models"
)
+
func AddString(e Execer, s models.String) error {
_, err := e.Exec(
`insert into strings (
did,
···
return err
}
+
func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) {
+
var all []models.String
var conditions []string
var args []any
···
defer rows.Close()
for rows.Next() {
+
var s models.String
var createdAt string
var editedAt sql.NullString
···
_, err := e.Exec(query, args...)
return err
}
+2 -2
appview/ingester.go
···
return err
}
-
string := db.StringFromRecord(did, rkey, record)
-
if err = string.Validate(); err != nil {
l.Error("invalid record", "err", err)
return err
}
···
return err
}
+
string := models.StringFromRecord(did, rkey, record)
+
if err = i.Validator.ValidateString(&string); err != nil {
l.Error("invalid record", "err", err)
return err
}
+95
appview/models/string.go
···
···
+
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
+
}
+
}
+
}
+2 -3
appview/notify/merged_notifier.go
···
import (
"context"
-
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
)
···
}
}
-
func (m *mergedNotifier) NewString(ctx context.Context, string *db.String) {
for _, notifier := range m.notifiers {
notifier.NewString(ctx, string)
}
}
-
func (m *mergedNotifier) EditString(ctx context.Context, string *db.String) {
for _, notifier := range m.notifiers {
notifier.EditString(ctx, string)
}
···
import (
"context"
"tangled.org/core/appview/models"
)
···
}
}
+
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 *models.String) {
for _, notifier := range m.notifiers {
notifier.EditString(ctx, string)
}
+4 -5
appview/notify/notifier.go
···
import (
"context"
-
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
)
···
UpdateProfile(ctx context.Context, profile *models.Profile)
-
NewString(ctx context.Context, s *db.String)
-
EditString(ctx context.Context, s *db.String)
DeleteString(ctx context.Context, did, rkey string)
}
···
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) DeleteString(ctx context.Context, did, rkey string) {}
···
import (
"context"
"tangled.org/core/appview/models"
)
···
UpdateProfile(ctx context.Context, profile *models.Profile)
+
NewString(ctx context.Context, s *models.String)
+
EditString(ctx context.Context, s *models.String)
DeleteString(ctx context.Context, did, rkey string)
}
···
func (m *BaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {}
+
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) {}
+6 -6
appview/pages/pages.go
···
type ProfileStringsParams struct {
LoggedInUser *oauth.User
-
Strings []db.String
Card *ProfileCard
Active string
}
···
Action string
// this is supplied in the case of editing an existing string
-
String db.String
}
func (p *Pages) PutString(w io.Writer, params PutStringParams) error {
···
type StringsDashboardParams struct {
LoggedInUser *oauth.User
Card ProfileCard
-
Strings []db.String
}
func (p *Pages) StringsDashboard(w io.Writer, params StringsDashboardParams) error {
···
type StringTimelineParams struct {
LoggedInUser *oauth.User
-
Strings []db.String
}
func (p *Pages) StringsTimeline(w io.Writer, params StringTimelineParams) error {
···
ShowRendered bool
RenderToggle bool
RenderedContents template.HTML
-
String db.String
-
Stats db.StringStats
Owner identity.Identity
}
···
type ProfileStringsParams struct {
LoggedInUser *oauth.User
+
Strings []models.String
Card *ProfileCard
Active string
}
···
Action string
// this is supplied in the case of editing an existing string
+
String models.String
}
func (p *Pages) PutString(w io.Writer, params PutStringParams) error {
···
type StringsDashboardParams struct {
LoggedInUser *oauth.User
Card ProfileCard
+
Strings []models.String
}
func (p *Pages) StringsDashboard(w io.Writer, params StringsDashboardParams) error {
···
type StringTimelineParams struct {
LoggedInUser *oauth.User
+
Strings []models.String
}
func (p *Pages) StringsTimeline(w io.Writer, params StringTimelineParams) error {
···
ShowRendered bool
RenderToggle bool
RenderedContents template.HTML
+
String models.String
+
Stats models.StringStats
Owner identity.Identity
}
+2 -3
appview/posthog/notifier.go
···
"log"
"github.com/posthog/posthog-go"
-
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
)
···
}
}
-
func (n *posthogNotifier) EditString(ctx context.Context, string *db.String) {
err := n.client.Enqueue(posthog.Capture{
DistinctId: string.Did.String(),
Event: "edit_string",
···
}
}
-
func (n *posthogNotifier) CreateString(ctx context.Context, string *db.String) {
err := n.client.Enqueue(posthog.Capture{
DistinctId: string.Did.String(),
Event: "create_string",
···
"log"
"github.com/posthog/posthog-go"
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
)
···
}
}
+
func (n *posthogNotifier) EditString(ctx context.Context, string *models.String) {
err := n.client.Enqueue(posthog.Capture{
DistinctId: string.Did.String(),
Event: "edit_string",
···
}
}
+
func (n *posthogNotifier) CreateString(ctx context.Context, string models.String) {
err := n.client.Enqueue(posthog.Capture{
DistinctId: string.Did.String(),
Event: "create_string",
+3 -2
appview/strings/strings.go
···
"tangled.org/core/api/tangled"
"tangled.org/core/appview/db"
"tangled.org/core/appview/middleware"
"tangled.org/core/appview/notify"
"tangled.org/core/appview/oauth"
"tangled.org/core/appview/pages"
···
description := r.FormValue("description")
// construct new string from form values
-
entry := db.String{
Did: first.Did,
Rkey: first.Rkey,
Filename: filename,
···
description := r.FormValue("description")
-
string := db.String{
Did: syntax.DID(user.Did),
Rkey: tid.TID(),
Filename: filename,
···
"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"
···
description := r.FormValue("description")
// construct new string from form values
+
entry := models.String{
Did: first.Did,
Rkey: first.Rkey,
Filename: filename,
···
description := r.FormValue("description")
+
string := models.String{
Did: syntax.DID(user.Did),
Rkey: tid.TID(),
Filename: filename,
+27
appview/validator/string.go
···
···
+
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
+
}