mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[feature] Fetch + display custom emoji in statuses from remote instances (#807)
* start implementing remote emoji fetcher * update status where pk * aaa * tidy up a little * check size limits for emojis * thank you linter, i love you <3 * update swagger docs * add emoji dereference test * make emoji max sizes configurable * normalize db.ErrAlreadyExists
This commit is contained in:
@@ -19,7 +19,7 @@ func processPostgresError(err error) db.Error {
|
||||
// (https://www.postgresql.org/docs/10/errcodes-appendix.html)
|
||||
switch pgErr.Code {
|
||||
case "23505" /* unique_violation */ :
|
||||
return db.NewErrAlreadyExists(pgErr.Message)
|
||||
return db.ErrAlreadyExists
|
||||
default:
|
||||
return err
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func processSQLiteError(err error) db.Error {
|
||||
// Handle supplied error code:
|
||||
switch sqliteErr.Code() {
|
||||
case sqlite3.SQLITE_CONSTRAINT_UNIQUE, sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY:
|
||||
return db.NewErrAlreadyExists(err.Error())
|
||||
return db.ErrAlreadyExists
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import (
|
||||
"container/list"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/cache"
|
||||
@@ -175,6 +176,57 @@ func (s *statusDB) PutStatus(ctx context.Context, status *gtsmodel.Status) db.Er
|
||||
})
|
||||
}
|
||||
|
||||
func (s *statusDB) UpdateStatus(ctx context.Context, status *gtsmodel.Status) (*gtsmodel.Status, db.Error) {
|
||||
err := s.conn.RunInTx(ctx, func(tx bun.Tx) error {
|
||||
// create links between this status and any emojis it uses
|
||||
for _, i := range status.EmojiIDs {
|
||||
if _, err := tx.NewInsert().Model(>smodel.StatusToEmoji{
|
||||
StatusID: status.ID,
|
||||
EmojiID: i,
|
||||
}).Exec(ctx); err != nil {
|
||||
err = s.conn.errProc(err)
|
||||
if !errors.Is(err, db.ErrAlreadyExists) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create links between this status and any tags it uses
|
||||
for _, i := range status.TagIDs {
|
||||
if _, err := tx.NewInsert().Model(>smodel.StatusToTag{
|
||||
StatusID: status.ID,
|
||||
TagID: i,
|
||||
}).Exec(ctx); err != nil {
|
||||
err = s.conn.errProc(err)
|
||||
if !errors.Is(err, db.ErrAlreadyExists) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// change the status ID of the media attachments to this status
|
||||
for _, a := range status.Attachments {
|
||||
a.StatusID = status.ID
|
||||
a.UpdatedAt = time.Now()
|
||||
if _, err := tx.NewUpdate().Model(a).
|
||||
Where("id = ?", a.ID).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, update the status itself
|
||||
if _, err := tx.NewUpdate().Model(status).WherePK().Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Put(status)
|
||||
return nil
|
||||
})
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (s *statusDB) GetStatusParents(ctx context.Context, status *gtsmodel.Status, onlyDirect bool) ([]*gtsmodel.Status, db.Error) {
|
||||
parents := []*gtsmodel.Status{}
|
||||
s.statusParent(ctx, status, &parents, onlyDirect)
|
||||
|
@@ -35,4 +35,6 @@ type Emoji interface {
|
||||
// GetEmojiByShortcodeDomain gets an emoji based on its shortcode and domain.
|
||||
// For local emoji, domain should be an empty string.
|
||||
GetEmojiByShortcodeDomain(ctx context.Context, shortcode string, domain string) (*gtsmodel.Emoji, Error)
|
||||
// GetEmojiByURI returns one emoji based on its ActivityPub URI.
|
||||
GetEmojiByURI(ctx context.Context, uri string) (*gtsmodel.Emoji, Error)
|
||||
}
|
||||
|
@@ -28,19 +28,8 @@ var (
|
||||
ErrNoEntries Error = fmt.Errorf("no entries")
|
||||
// ErrMultipleEntries is returned when a caller expected ONE entry for a query, but multiples were found.
|
||||
ErrMultipleEntries Error = fmt.Errorf("multiple entries")
|
||||
// ErrAlreadyExists is returned when a conflict was encountered in the db when doing an insert.
|
||||
ErrAlreadyExists Error = fmt.Errorf("already exists")
|
||||
// ErrUnknown denotes an unknown database error.
|
||||
ErrUnknown Error = fmt.Errorf("unknown error")
|
||||
)
|
||||
|
||||
// ErrAlreadyExists is returned when a caller tries to insert a database entry that already exists in the db.
|
||||
type ErrAlreadyExists struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *ErrAlreadyExists) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func NewErrAlreadyExists(msg string) error {
|
||||
return &ErrAlreadyExists{message: msg}
|
||||
}
|
||||
|
@@ -38,6 +38,9 @@ type Status interface {
|
||||
// PutStatus stores one status in the database.
|
||||
PutStatus(ctx context.Context, status *gtsmodel.Status) Error
|
||||
|
||||
// UpdateStatus updates one status in the database and returns it to the caller.
|
||||
UpdateStatus(ctx context.Context, status *gtsmodel.Status) (*gtsmodel.Status, Error)
|
||||
|
||||
// CountStatusReplies returns the amount of replies recorded for a status, or an error if something goes wrong
|
||||
CountStatusReplies(ctx context.Context, status *gtsmodel.Status) (int, Error)
|
||||
|
||||
|
Reference in New Issue
Block a user