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.
This commit is contained in:
Kailash Nadh 2023-05-08 20:28:25 +05:30
parent be16297549
commit 9ffc912a2c
4 changed files with 37 additions and 8 deletions

View file

@ -19,8 +19,8 @@ func (c *Core) GetAllMedia(provider string, s media.Store) ([]media.Media, error
} }
for i := 0; i < len(out); i++ { for i := 0; i < len(out); i++ {
out[i].URL = s.Get(out[i].Filename) out[i].URL = s.GetURL(out[i].Filename)
out[i].ThumbURL = s.Get(out[i].Thumb) out[i].ThumbURL = s.GetURL(out[i].Thumb)
} }
return out, nil 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))) c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.media}", "error", pqErrMsg(err)))
} }
out.URL = s.Get(out.Filename) out.URL = s.GetURL(out.Filename)
out.ThumbURL = s.Get(out.Thumb) out.ThumbURL = s.GetURL(out.Thumb)
return out, nil return out, nil
} }

View file

@ -24,5 +24,6 @@ type Media struct {
type Store interface { type Store interface {
Put(string, string, io.ReadSeeker) (string, error) Put(string, string, io.ReadSeeker) (string, error)
Delete(string) error Delete(string) error
Get(string) string GetURL(string) string
GetBlob(string) ([]byte, error)
} }

View file

@ -4,6 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -59,11 +60,17 @@ func (c *Client) Put(filename string, cType string, src io.ReadSeeker) (string,
return filename, nil return filename, nil
} }
// Get accepts a filename and retrieves the full path from disk. // GetURL accepts a filename and retrieves the full path from disk.
func (c *Client) Get(name string) string { func (c *Client) GetURL(name string) string {
return fmt.Sprintf("%s%s/%s", c.opts.RootURL, c.opts.UploadURI, name) 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. // Delete accepts a filename and removes it from disk.
func (c *Client) Delete(file string) error { func (c *Client) Delete(file string) error {
dir := getDir(c.opts.UploadPath) dir := getDir(c.opts.UploadPath)

View file

@ -3,6 +3,8 @@ package s3
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"path/filepath"
"strings" "strings"
"time" "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. // 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 // Generate a private S3 pre-signed URL if it's a private bucket, and there
// is no public URL provided. // is no public URL provided.
if c.opts.BucketType == "private" && c.opts.PublicURL == "" { if c.opts.BucketType == "private" && c.opts.PublicURL == "" {
@ -99,6 +101,25 @@ func (c *Client) Get(name string) string {
return c.makeFileURL(name) 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. // Delete accepts the filename of the object and deletes from S3.
func (c *Client) Delete(name string) error { func (c *Client) Delete(name string) error {
err := c.s3.FileDelete(simples3.DeleteInput{ err := c.s3.FileDelete(simples3.DeleteInput{