[chore] Text formatting overhaul (#1406)

* Implement goldmark debug print for hashtags and mentions

* Minify HTML in FromPlain

* Convert plaintext status parser to goldmark

* Move mention/tag/emoji finding logic into formatter

* Combine mention and hashtag boundary characters

* Normalize unicode when rendering hashtags
This commit is contained in:
Autumn! 2023-02-03 10:58:58 +00:00 committed by GitHub
commit 49beb17a8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 826 additions and 1314 deletions

View file

@ -473,43 +473,40 @@ func sqlitePragmas(ctx context.Context, conn *DBConn) error {
CONVERSION FUNCTIONS
*/
func (dbService *DBService) TagStringsToTags(ctx context.Context, tags []string, originAccountID string) ([]*gtsmodel.Tag, error) {
func (dbService *DBService) TagStringToTag(ctx context.Context, t string, originAccountID string) (*gtsmodel.Tag, error) {
protocol := config.GetProtocol()
host := config.GetHost()
now := time.Now()
newTags := []*gtsmodel.Tag{}
for _, t := range tags {
tag := &gtsmodel.Tag{}
// we can use selectorinsert here to create the new tag if it doesn't exist already
// inserted will be true if this is a new tag we just created
if err := dbService.conn.NewSelect().Model(tag).Where("LOWER(?) = LOWER(?)", bun.Ident("name"), t).Scan(ctx); err != nil {
if err == sql.ErrNoRows {
// tag doesn't exist yet so populate it
newID, err := id.NewRandomULID()
if err != nil {
return nil, err
}
tag.ID = newID
tag.URL = fmt.Sprintf("%s://%s/tags/%s", protocol, host, t)
tag.Name = t
tag.FirstSeenFromAccountID = originAccountID
tag.CreatedAt = time.Now()
tag.UpdatedAt = time.Now()
useable := true
tag.Useable = &useable
listable := true
tag.Listable = &listable
} else {
return nil, fmt.Errorf("error getting tag with name %s: %s", t, err)
}
}
// bail already if the tag isn't useable
if !*tag.Useable {
continue
}
tag.LastStatusAt = time.Now()
newTags = append(newTags, tag)
tag := &gtsmodel.Tag{}
// we can use selectorinsert here to create the new tag if it doesn't exist already
// inserted will be true if this is a new tag we just created
if err := dbService.conn.NewSelect().Model(tag).Where("LOWER(?) = LOWER(?)", bun.Ident("name"), t).Scan(ctx); err != nil && err != sql.ErrNoRows {
return nil, fmt.Errorf("error getting tag with name %s: %s", t, err)
}
return newTags, nil
if tag.ID == "" {
// tag doesn't exist yet so populate it
newID, err := id.NewRandomULID()
if err != nil {
return nil, err
}
tag.ID = newID
tag.URL = protocol + "://" + host + "/tags/" + t
tag.Name = t
tag.FirstSeenFromAccountID = originAccountID
tag.CreatedAt = now
tag.UpdatedAt = now
useable := true
tag.Useable = &useable
listable := true
tag.Listable = &listable
}
// bail already if the tag isn't useable
if !*tag.Useable {
return nil, fmt.Errorf("tag %s is not useable", t)
}
tag.LastStatusAt = now
return tag, nil
}

View file

@ -52,12 +52,12 @@ type DB interface {
USEFUL CONVERSION FUNCTIONS
*/
// TagStringsToTags takes a slice of deduplicated, lowercase tags in the form "somehashtag", which have been
// TagStringToTag takes a lowercase tag in the form "somehashtag", which has been
// used in a status. It takes the id of the account that wrote the status, and the id of the status itself, and then
// returns a slice of *apimodel.Tag corresponding to the given tags. If the tag already exists in database, that tag
// returns an *apimodel.Tag corresponding to the given tags. If the tag already exists in database, that tag
// will be returned. Otherwise a pointer to a new tag struct will be created and returned.
//
// Note: this func doesn't/shouldn't do any manipulation of the tags in the DB, it's just for checking
// Note: this func doesn't/shouldn't do any manipulation of tags in the DB, it's just for checking
// if they exist in the db already, and conveniently returning them, or creating new tag structs.
TagStringsToTags(ctx context.Context, tags []string, originAccountID string) ([]*gtsmodel.Tag, error)
TagStringToTag(ctx context.Context, tag string, originAccountID string) (*gtsmodel.Tag, error)
}