Add methods to upload images to a subreddit
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
parent
5343dfc40d
commit
77d0d257d3
2 changed files with 381 additions and 63 deletions
|
@ -6,8 +6,12 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
|
@ -840,54 +844,6 @@ func (s *SubredditService) UpdateStyleSheet(ctx context.Context, subreddit, styl
|
|||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveHeaderImage removes the subreddit's custom header image.
|
||||
// The call succeeds even if there's no header image.
|
||||
func (s *SubredditService) RemoveHeaderImage(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_header", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveMobileIcon removes the subreddit's custom mobile icon.
|
||||
// The call succeeds even if there's no mobile icon.
|
||||
func (s *SubredditService) RemoveMobileIcon(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_icon", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveMobileBanner removes the subreddit's custom mobile banner.
|
||||
// The call succeeds even if there's no mobile banner.
|
||||
func (s *SubredditService) RemoveMobileBanner(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_banner", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveImage removes an image from the subreddit's custom image set.
|
||||
// The call succeeds even if the named image does not exist.
|
||||
func (s *SubredditService) RemoveImage(ctx context.Context, subreddit, imageName string) (*Response, error) {
|
||||
|
@ -904,3 +860,145 @@ func (s *SubredditService) RemoveImage(ctx context.Context, subreddit, imageName
|
|||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveHeader removes the subreddit's current header image.
|
||||
// The call succeeds even if there's no header image.
|
||||
func (s *SubredditService) RemoveHeader(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_header", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveMobileHeader removes the subreddit's current mobile header.
|
||||
// The call succeeds even if there's no mobile header.
|
||||
func (s *SubredditService) RemoveMobileHeader(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_banner", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RemoveMobileIcon removes the subreddit's current mobile icon.
|
||||
// The call succeeds even if there's no mobile icon.
|
||||
func (s *SubredditService) RemoveMobileIcon(ctx context.Context, subreddit string) (*Response, error) {
|
||||
path := fmt.Sprintf("r/%s/api/delete_sr_icon", subreddit)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
req, err := s.client.NewRequest(http.MethodPost, path, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
func (s *SubredditService) uploadImage(ctx context.Context, subreddit, imagePath, imageType, imageName string) (string, *Response, error) {
|
||||
file, err := os.Open(imagePath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("upload_type", imageType)
|
||||
form.Set("name", imageName)
|
||||
form.Set("img_type", "png")
|
||||
|
||||
ext := filepath.Ext(file.Name())
|
||||
if strings.EqualFold(ext, ".jpg") {
|
||||
form.Set("img_type", "jpg")
|
||||
}
|
||||
|
||||
body := new(bytes.Buffer)
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
for k := range form {
|
||||
writer.WriteField(k, form.Get(k))
|
||||
}
|
||||
|
||||
part, err := writer.CreateFormFile("file", file.Name())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
_, err = io.Copy(part, file)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("r/%s/api/upload_sr_img", subreddit)
|
||||
u, err := s.client.BaseURL.Parse(path)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), body)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
req.Header.Set(headerContentType, writer.FormDataContentType())
|
||||
|
||||
root := new(struct {
|
||||
Errors []string `json:"errors"`
|
||||
ErrorValues []string `json:"errors_values"`
|
||||
ImageSource string `json:"img_src"`
|
||||
})
|
||||
resp, err := s.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return "", resp, err
|
||||
}
|
||||
|
||||
if len(root.ErrorValues) > 0 {
|
||||
err = fmt.Errorf("could not upload image: %s", strings.Join(root.ErrorValues, "; "))
|
||||
return "", resp, err
|
||||
}
|
||||
|
||||
return root.ImageSource, resp, nil
|
||||
}
|
||||
|
||||
// UploadImage uploads an image to the subreddit.
|
||||
// If an image with the image name already exists, it it replaced.
|
||||
// A successful call returns a link to the uploaded image.
|
||||
func (s *SubredditService) UploadImage(ctx context.Context, subreddit, imagePath, imageName string) (string, *Response, error) {
|
||||
return s.uploadImage(ctx, subreddit, imagePath, "img", imageName)
|
||||
}
|
||||
|
||||
// UploadHeader uploads an image to be user as the subreddit's header image.
|
||||
// A successful call returns a link to the uploaded image.
|
||||
func (s *SubredditService) UploadHeader(ctx context.Context, subreddit, imagePath, imageName string) (string, *Response, error) {
|
||||
return s.uploadImage(ctx, subreddit, imagePath, "header", imageName)
|
||||
}
|
||||
|
||||
// UploadMobileHeader uploads an image to be user as the subreddit's mobile header image.
|
||||
// A successful call returns a link to the uploaded image.
|
||||
func (s *SubredditService) UploadMobileHeader(ctx context.Context, subreddit, imagePath, imageName string) (string, *Response, error) {
|
||||
return s.uploadImage(ctx, subreddit, imagePath, "banner", imageName)
|
||||
}
|
||||
|
||||
// UploadMobileIcon uploads an image to be user as the subreddit's mobile icon.
|
||||
// A successful call returns a link to the uploaded image.
|
||||
func (s *SubredditService) UploadMobileIcon(ctx context.Context, subreddit, imagePath, imageName string) (string, *Response, error) {
|
||||
return s.uploadImage(ctx, subreddit, imagePath, "icon", imageName)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package reddit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -1227,7 +1231,27 @@ func TestSubredditService_UpdateStyleSheet(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSubredditService_RemoveHeaderImage(t *testing.T) {
|
||||
func TestSubredditService_RemoveImage(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/delete_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
form.Set("img_name", "testimage")
|
||||
|
||||
err := r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
})
|
||||
|
||||
_, err := client.Subreddit.RemoveImage(ctx, "testsubreddit", "testimage")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSubredditService_RemoveHeader(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
|
@ -1242,7 +1266,26 @@ func TestSubredditService_RemoveHeaderImage(t *testing.T) {
|
|||
require.Equal(t, form, r.PostForm)
|
||||
})
|
||||
|
||||
_, err := client.Subreddit.RemoveHeaderImage(ctx, "testsubreddit")
|
||||
_, err := client.Subreddit.RemoveHeader(ctx, "testsubreddit")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSubredditService_RemoveMobileHeader(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/delete_sr_banner", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
|
||||
err := r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
})
|
||||
|
||||
_, err := client.Subreddit.RemoveMobileHeader(ctx, "testsubreddit")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@ -1265,41 +1308,218 @@ func TestSubredditService_RemoveMobileIcon(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSubredditService_RemoveMobileBanner(t *testing.T) {
|
||||
func TestSubredditService_UploadImage(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/delete_sr_banner", func(w http.ResponseWriter, r *http.Request) {
|
||||
imageFile, err := ioutil.TempFile("/tmp", "emoji*.png")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
imageFile.Close()
|
||||
os.Remove(imageFile.Name())
|
||||
}()
|
||||
|
||||
_, err = imageFile.WriteString("this is a test")
|
||||
require.NoError(t, err)
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/upload_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
_, file, err := r.FormFile("file")
|
||||
require.NoError(t, err)
|
||||
|
||||
err := r.ParseForm()
|
||||
rdr, err := file.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, rdr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "this is a test", buf.String())
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("upload_type", "img")
|
||||
form.Set("name", "testname")
|
||||
form.Set("img_type", "png")
|
||||
|
||||
err = r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"img_src": "https://example.com/test.png"
|
||||
}`)
|
||||
})
|
||||
|
||||
_, err := client.Subreddit.RemoveMobileBanner(ctx, "testsubreddit")
|
||||
link, _, err := client.Subreddit.UploadImage(ctx, "testsubreddit", imageFile.Name(), "testname")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://example.com/test.png", link)
|
||||
}
|
||||
|
||||
func TestSubredditService_RemoveImage(t *testing.T) {
|
||||
func TestSubredditService_UploadHeader(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/delete_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
imageFile, err := ioutil.TempFile("/tmp", "emoji*.png")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
imageFile.Close()
|
||||
os.Remove(imageFile.Name())
|
||||
}()
|
||||
|
||||
_, err = imageFile.WriteString("this is a test")
|
||||
require.NoError(t, err)
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/upload_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("api_type", "json")
|
||||
form.Set("img_name", "testimage")
|
||||
_, file, err := r.FormFile("file")
|
||||
require.NoError(t, err)
|
||||
|
||||
err := r.ParseForm()
|
||||
rdr, err := file.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, rdr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "this is a test", buf.String())
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("upload_type", "header")
|
||||
form.Set("name", "testname")
|
||||
form.Set("img_type", "png")
|
||||
|
||||
err = r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"img_src": "https://example.com/test.png"
|
||||
}`)
|
||||
})
|
||||
|
||||
_, err := client.Subreddit.RemoveImage(ctx, "testsubreddit", "testimage")
|
||||
link, _, err := client.Subreddit.UploadHeader(ctx, "testsubreddit", imageFile.Name(), "testname")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://example.com/test.png", link)
|
||||
}
|
||||
|
||||
func TestSubredditService_UploadMobileHeader(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
imageFile, err := ioutil.TempFile("/tmp", "emoji*.png")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
imageFile.Close()
|
||||
os.Remove(imageFile.Name())
|
||||
}()
|
||||
|
||||
_, err = imageFile.WriteString("this is a test")
|
||||
require.NoError(t, err)
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/upload_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
_, file, err := r.FormFile("file")
|
||||
require.NoError(t, err)
|
||||
|
||||
rdr, err := file.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, rdr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "this is a test", buf.String())
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("upload_type", "banner")
|
||||
form.Set("name", "testname")
|
||||
form.Set("img_type", "png")
|
||||
|
||||
err = r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"img_src": "https://example.com/test.png"
|
||||
}`)
|
||||
})
|
||||
|
||||
link, _, err := client.Subreddit.UploadMobileHeader(ctx, "testsubreddit", imageFile.Name(), "testname")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://example.com/test.png", link)
|
||||
}
|
||||
|
||||
func TestSubredditService_UploadMobileIcon(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
imageFile, err := ioutil.TempFile("/tmp", "emoji*.jpg")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
imageFile.Close()
|
||||
os.Remove(imageFile.Name())
|
||||
}()
|
||||
|
||||
_, err = imageFile.WriteString("this is a test")
|
||||
require.NoError(t, err)
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/upload_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
_, file, err := r.FormFile("file")
|
||||
require.NoError(t, err)
|
||||
|
||||
rdr, err := file.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, rdr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "this is a test", buf.String())
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("upload_type", "icon")
|
||||
form.Set("name", "testname")
|
||||
form.Set("img_type", "jpg")
|
||||
|
||||
err = r.ParseForm()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, form, r.PostForm)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"img_src": "https://example.com/test.jpg"
|
||||
}`)
|
||||
})
|
||||
|
||||
link, _, err := client.Subreddit.UploadMobileIcon(ctx, "testsubreddit", imageFile.Name(), "testname")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://example.com/test.jpg", link)
|
||||
}
|
||||
|
||||
func TestSubredditService_UploadImage_Error(t *testing.T) {
|
||||
client, mux, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
imageFile, err := ioutil.TempFile("/tmp", "emoji*.jpg")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
imageFile.Close()
|
||||
os.Remove(imageFile.Name())
|
||||
}()
|
||||
|
||||
mux.HandleFunc("/r/testsubreddit/api/upload_sr_img", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
fmt.Fprint(w, `{
|
||||
"errors_values": [
|
||||
"error one",
|
||||
"error two"
|
||||
]
|
||||
}`)
|
||||
})
|
||||
|
||||
_, _, err = client.Subreddit.UploadImage(ctx, "testsubreddit", "does-not-exist.jpg", "testname")
|
||||
require.EqualError(t, err, "open does-not-exist.jpg: no such file or directory")
|
||||
|
||||
_, _, err = client.Subreddit.UploadImage(ctx, "testsubreddit", imageFile.Name(), "testname")
|
||||
require.EqualError(t, err, "could not upload image: error one; error two")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue