Started working on emoji
@ -36,6 +36,10 @@ const (
|
|||||||
mediaTypeKey = "media_type"
|
mediaTypeKey = "media_type"
|
||||||
mediaSizeKey = "media_size"
|
mediaSizeKey = "media_size"
|
||||||
fileNameKey = "file_name"
|
fileNameKey = "file_name"
|
||||||
|
shortcodeKey = "shortcode"
|
||||||
|
|
||||||
|
emojisPath = "emojis"
|
||||||
|
filesPath = "files"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileServer implements the RESTAPIModule interface.
|
// fileServer implements the RESTAPIModule interface.
|
||||||
@ -62,6 +66,7 @@ func New(config *config.Config, db db.DB, storage storage.Storage, log *logrus.L
|
|||||||
// Route satisfies the RESTAPIModule interface
|
// Route satisfies the RESTAPIModule interface
|
||||||
func (m *fileServer) Route(s router.Router) error {
|
func (m *fileServer) Route(s router.Router) error {
|
||||||
s.AttachHandler(http.MethodGet, fmt.Sprintf("%s/:%s/:%s/:%s/:%s", m.storageBase, accountIDKey, mediaTypeKey, mediaSizeKey, fileNameKey), m.ServeFile)
|
s.AttachHandler(http.MethodGet, fmt.Sprintf("%s/:%s/:%s/:%s/:%s", m.storageBase, accountIDKey, mediaTypeKey, mediaSizeKey, fileNameKey), m.ServeFile)
|
||||||
|
s.AttachHandler(http.MethodGet, fmt.Sprintf("%s/:%s/:%s/:%s/:%s", m.storageBase, accountIDKey, mediaTypeKey, mediaSizeKey, fileNameKey), m.serveEmoji)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
internal/apimodule/fileserver/serveemoji.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package fileserver
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func (m *fileServer) serveEmoji(c *gin.Context) {
|
||||||
|
|
||||||
|
}
|
||||||
@ -111,6 +111,10 @@ type DB interface {
|
|||||||
HANDY SHORTCUTS
|
HANDY SHORTCUTS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// CreateInstanceAccount creates an account in the database with the same username as the instance host value.
|
||||||
|
// Ie., if the instance is hosted at 'example.org' the instance user will have a username of 'example.org'.
|
||||||
|
CreateInstanceAccount() error
|
||||||
|
|
||||||
// GetAccountByUserID is a shortcut for the common action of fetching an account corresponding to a user ID.
|
// GetAccountByUserID is a shortcut for the common action of fetching an account corresponding to a user ID.
|
||||||
// The given account pointer will be set to the result of the query, whatever it is.
|
// The given account pointer will be set to the result of the query, whatever it is.
|
||||||
// In case of no entries, a 'no entries' error will be returned
|
// In case of no entries, a 'no entries' error will be returned
|
||||||
|
|||||||
@ -21,17 +21,41 @@ package gtsmodel
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Emoji struct {
|
type Emoji struct {
|
||||||
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
|
// database ID of this emoji
|
||||||
Shortcode string `pg:"notnull"`
|
ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull"`
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
// String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
// eg., 'blob_hug' 'purple_heart' Must be unique with domain.
|
||||||
ImageFileName string
|
Shortcode string `pg:"notnull,unique:shortcodedomain"`
|
||||||
ImageContentType string
|
// Origin domain of this emoji, eg 'example.org', 'queer.party'. Null for local emojis.
|
||||||
ImageFileSize string
|
Domain string `pg:",unique:shortcodedomain"`
|
||||||
ImageUpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
// When was this emoji created. Must be unique with shortcode.
|
||||||
Disabled bool
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
URI string
|
// When was this emoji updated
|
||||||
ImageRemoteURL string
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
VisibleInPicker bool
|
// Where can this emoji be retrieved remotely? Null for local emojis.
|
||||||
CategoryID string
|
// For remote emojis, it'll be something like:
|
||||||
|
// https://hackers.town/system/custom_emojis/images/000/049/842/original/1b74481204feabfd.png
|
||||||
|
ImageRemoteURL string
|
||||||
|
// Where can this emoji be retrieved from the local server? Null for remote emojis.
|
||||||
|
// Assuming our server is hosted at 'example.org', this will be something like:
|
||||||
|
// 'https://example.org/fileserver/emojis/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png'
|
||||||
|
ImageURL string
|
||||||
|
// Path of the emoji image in the server storage system.
|
||||||
|
// Will be something like '/gotosocial/storage/emojis/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png'
|
||||||
|
ImagePath string `pg:",notnull"`
|
||||||
|
// MIME content type of the emoji image
|
||||||
|
// Probably "image/png"
|
||||||
|
ImageContentType string `pg:",notnull"`
|
||||||
|
// Size of the emoji image file in bytes, for serving purposes.
|
||||||
|
ImageFileSize int `pg:",notnull"`
|
||||||
|
// When was the emoji image last updated?
|
||||||
|
ImageUpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
|
// Has a moderation action disabled this emoji from being shown?
|
||||||
|
Disabled bool `pg:",notnull,default:false"`
|
||||||
|
// ActivityStreams uri of this emoji. Something like 'https://example.org/emojis/1234'
|
||||||
|
URI string `pg:",notnull,unique"`
|
||||||
|
// Is this emoji visible in the admin emoji picker?
|
||||||
|
VisibleInPicker bool `pg:",notnull,default:true"`
|
||||||
|
// In which emoji category is this emoji visible?
|
||||||
|
CategoryID string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -312,6 +312,23 @@ func (ps *postgresService) DeleteWhere(key string, value interface{}, i interfac
|
|||||||
HANDY SHORTCUTS
|
HANDY SHORTCUTS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
func (ps *postgresService) CreateInstanceAccount() error {
|
||||||
|
username := ps.config.Host
|
||||||
|
instanceAccount := >smodel.Account{
|
||||||
|
Username: username,
|
||||||
|
}
|
||||||
|
inserted, err := ps.conn.Model(instanceAccount).Where("username = ?", username).SelectOrInsert();
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if inserted {
|
||||||
|
ps.log.Infof("created instance account %s with id %s",username, instanceAccount.ID)
|
||||||
|
} else {
|
||||||
|
ps.log.Infof("instance account %s already exists with id %s", username, instanceAccount.ID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ps *postgresService) GetAccountByUserID(userID string, account *gtsmodel.Account) error {
|
func (ps *postgresService) GetAccountByUserID(userID string, account *gtsmodel.Account) error {
|
||||||
user := >smodel.User{
|
user := >smodel.User{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
|
|||||||
@ -38,6 +38,7 @@ const (
|
|||||||
MediaAttachment = "attachment"
|
MediaAttachment = "attachment"
|
||||||
MediaHeader = "header"
|
MediaHeader = "header"
|
||||||
MediaAvatar = "avatar"
|
MediaAvatar = "avatar"
|
||||||
|
MediaEmoji = "emoji"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MediaHandler provides an interface for parsing, storing, and retrieving media objects like photos, videos, and gifs.
|
// MediaHandler provides an interface for parsing, storing, and retrieving media objects like photos, videos, and gifs.
|
||||||
|
|||||||
@ -58,6 +58,10 @@ func NewTestDB() db.DB {
|
|||||||
|
|
||||||
// StandardDBSetup populates a given db with all the necessary tables/models for perfoming tests.
|
// StandardDBSetup populates a given db with all the necessary tables/models for perfoming tests.
|
||||||
func StandardDBSetup(db db.DB) {
|
func StandardDBSetup(db db.DB) {
|
||||||
|
if err := db.CreateInstanceAccount(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range testModels {
|
for _, m := range testModels {
|
||||||
if err := db.CreateTable(m); err != nil {
|
if err := db.CreateTable(m); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 293 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 263 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |