From 9ffc912a2cb10b114947d01aaed218759e9b20cf Mon Sep 17 00:00:00 2001 From: Kailash Nadh Date: Mon, 8 May 2023 20:28:25 +0530 Subject: [PATCH] Refactor media provider. - Rename `Get()` to `GetURL()`. - Add `GetBlob()` to retrieve the media file blobs in filesystem and and s3 media providers. This enables reading media files inside listmonk paving the way to campaign file attachments. --- internal/core/media.go | 8 +++---- internal/media/media.go | 3 ++- .../media/providers/filesystem/filesystem.go | 11 +++++++-- internal/media/providers/s3/s3.go | 23 ++++++++++++++++++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/internal/core/media.go b/internal/core/media.go index a7c36687f..aa86330b1 100644 --- a/internal/core/media.go +++ b/internal/core/media.go @@ -19,8 +19,8 @@ func (c *Core) GetAllMedia(provider string, s media.Store) ([]media.Media, error } for i := 0; i < len(out); i++ { - out[i].URL = s.Get(out[i].Filename) - out[i].ThumbURL = s.Get(out[i].Thumb) + out[i].URL = s.GetURL(out[i].Filename) + out[i].ThumbURL = s.GetURL(out[i].Thumb) } return out, nil @@ -39,8 +39,8 @@ func (c *Core) GetMedia(id int, uuid string, s media.Store) (media.Media, error) c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.media}", "error", pqErrMsg(err))) } - out.URL = s.Get(out.Filename) - out.ThumbURL = s.Get(out.Thumb) + out.URL = s.GetURL(out.Filename) + out.ThumbURL = s.GetURL(out.Thumb) return out, nil } diff --git a/internal/media/media.go b/internal/media/media.go index 6e8230a42..fc67f60f1 100644 --- a/internal/media/media.go +++ b/internal/media/media.go @@ -24,5 +24,6 @@ type Media struct { type Store interface { Put(string, string, io.ReadSeeker) (string, error) Delete(string) error - Get(string) string + GetURL(string) string + GetBlob(string) ([]byte, error) } diff --git a/internal/media/providers/filesystem/filesystem.go b/internal/media/providers/filesystem/filesystem.go index d35c20113..c2e6b1b7f 100644 --- a/internal/media/providers/filesystem/filesystem.go +++ b/internal/media/providers/filesystem/filesystem.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "fmt" "io" + "io/ioutil" "os" "path/filepath" "regexp" @@ -59,11 +60,17 @@ func (c *Client) Put(filename string, cType string, src io.ReadSeeker) (string, return filename, nil } -// Get accepts a filename and retrieves the full path from disk. -func (c *Client) Get(name string) string { +// GetURL accepts a filename and retrieves the full path from disk. +func (c *Client) GetURL(name string) string { return fmt.Sprintf("%s%s/%s", c.opts.RootURL, c.opts.UploadURI, name) } +// GetBlob accepts a URL, reads the file, and returns the blob. +func (c *Client) GetBlob(url string) ([]byte, error) { + b, err := ioutil.ReadFile(filepath.Join(getDir(c.opts.UploadPath), filepath.Base(url))) + return b, err +} + // Delete accepts a filename and removes it from disk. func (c *Client) Delete(file string) error { dir := getDir(c.opts.UploadPath) diff --git a/internal/media/providers/s3/s3.go b/internal/media/providers/s3/s3.go index 3453583c7..7d9ffc38c 100644 --- a/internal/media/providers/s3/s3.go +++ b/internal/media/providers/s3/s3.go @@ -3,6 +3,8 @@ package s3 import ( "fmt" "io" + "io/ioutil" + "path/filepath" "strings" "time" @@ -80,7 +82,7 @@ func (c *Client) Put(name string, cType string, file io.ReadSeeker) (string, err } // Get accepts the filename of the object stored and retrieves from S3. -func (c *Client) Get(name string) string { +func (c *Client) GetURL(name string) string { // Generate a private S3 pre-signed URL if it's a private bucket, and there // is no public URL provided. if c.opts.BucketType == "private" && c.opts.PublicURL == "" { @@ -99,6 +101,25 @@ func (c *Client) Get(name string) string { return c.makeFileURL(name) } +// GetBlob reads a file from S3 and returns the raw bytes. +func (c *Client) GetBlob(url string) ([]byte, error) { + file, err := c.s3.FileDownload(simples3.DownloadInput{ + Bucket: c.opts.Bucket, + ObjectKey: c.makeBucketPath(filepath.Base(url)), + }) + if err != nil { + return nil, err + } + + b, err := ioutil.ReadAll(file) + if err != nil { + return nil, err + } + defer file.Close() + + return b, nil +} + // Delete accepts the filename of the object and deletes from S3. func (c *Client) Delete(name string) error { err := c.s3.FileDelete(simples3.DeleteInput{