mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
rest: Implement MarkSeen for #58
- message: Add MarkSeen to Manager, StoreManager. - rest: Add PATCH for /mailbox/name/id. - rest: Add MailboxMarkSeenV1 handler. - rest: Add Seen to model. - rest: Update handlers to set Seen. - rest: Add doJSONBody func.
This commit is contained in:
@@ -25,6 +25,7 @@ type Manager interface {
|
|||||||
) (id string, err error)
|
) (id string, err error)
|
||||||
GetMetadata(mailbox string) ([]*Metadata, error)
|
GetMetadata(mailbox string) ([]*Metadata, error)
|
||||||
GetMessage(mailbox, id string) (*Message, error)
|
GetMessage(mailbox, id string) (*Message, error)
|
||||||
|
MarkSeen(mailbox, id string) error
|
||||||
PurgeMessages(mailbox string) error
|
PurgeMessages(mailbox string) error
|
||||||
RemoveMessage(mailbox, id string) error
|
RemoveMessage(mailbox, id string) error
|
||||||
SourceReader(mailbox, id string) (io.ReadCloser, error)
|
SourceReader(mailbox, id string) (io.ReadCloser, error)
|
||||||
@@ -124,6 +125,11 @@ func (s *StoreManager) GetMessage(mailbox, id string) (*Message, error) {
|
|||||||
return &Message{Metadata: *header, env: env}, nil
|
return &Message{Metadata: *header, env: env}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkSeen marks the message as having been read.
|
||||||
|
func (s *StoreManager) MarkSeen(mailbox, id string) error {
|
||||||
|
return s.Store.MarkSeen(mailbox, id)
|
||||||
|
}
|
||||||
|
|
||||||
// PurgeMessages removes all messages from the specified mailbox.
|
// PurgeMessages removes all messages from the specified mailbox.
|
||||||
func (s *StoreManager) PurgeMessages(mailbox string) error {
|
func (s *StoreManager) PurgeMessages(mailbox string) error {
|
||||||
return s.Store.PurgeMessages(mailbox)
|
return s.Store.PurgeMessages(mailbox)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/pkg/rest/model"
|
"github.com/jhillyerd/inbucket/pkg/rest/model"
|
||||||
@@ -37,6 +38,7 @@ func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (
|
|||||||
Subject: msg.Subject,
|
Subject: msg.Subject,
|
||||||
Date: msg.Date,
|
Date: msg.Date,
|
||||||
Size: msg.Size,
|
Size: msg.Size,
|
||||||
|
Seen: msg.Seen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return web.RenderJSON(w, jmessages)
|
return web.RenderJSON(w, jmessages)
|
||||||
@@ -83,6 +85,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (
|
|||||||
Subject: msg.Subject,
|
Subject: msg.Subject,
|
||||||
Date: msg.Date,
|
Date: msg.Date,
|
||||||
Size: msg.Size,
|
Size: msg.Size,
|
||||||
|
Seen: msg.Seen,
|
||||||
Header: msg.Header(),
|
Header: msg.Header(),
|
||||||
Body: &model.JSONMessageBodyV1{
|
Body: &model.JSONMessageBodyV1{
|
||||||
Text: msg.Text(),
|
Text: msg.Text(),
|
||||||
@@ -92,6 +95,33 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MailboxMarkSeenV1 marks a message as read.
|
||||||
|
func MailboxMarkSeenV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
|
id := ctx.Vars["id"]
|
||||||
|
name, err := ctx.Manager.MailboxForAddress(ctx.Vars["name"])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(req.Body)
|
||||||
|
dm := model.JSONMessageHeaderV1{}
|
||||||
|
if err := dec.Decode(&dm); err != nil {
|
||||||
|
return fmt.Errorf("Failed to decode JSON: %v", err)
|
||||||
|
}
|
||||||
|
if dm.Seen {
|
||||||
|
err = ctx.Manager.MarkSeen(name, id)
|
||||||
|
if err == storage.ErrNotExist {
|
||||||
|
http.NotFound(w, req)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// This doesn't indicate empty, likely an IO error
|
||||||
|
return fmt.Errorf("MarkSeen(%q) failed: %v", id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return web.RenderJSON(w, "OK")
|
||||||
|
}
|
||||||
|
|
||||||
// MailboxPurgeV1 deletes all messages from a mailbox
|
// MailboxPurgeV1 deletes all messages from a mailbox
|
||||||
func MailboxPurgeV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
func MailboxPurgeV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
decodedStringEquals(t, result, "[0]/subject", "subject 1")
|
decodedStringEquals(t, result, "[0]/subject", "subject 1")
|
||||||
decodedStringEquals(t, result, "[0]/date", "2012-02-01T10:11:12.000000253-08:00")
|
decodedStringEquals(t, result, "[0]/date", "2012-02-01T10:11:12.000000253-08:00")
|
||||||
decodedNumberEquals(t, result, "[0]/size", 0)
|
decodedNumberEquals(t, result, "[0]/size", 0)
|
||||||
|
decodedBoolEquals(t, result, "[0]/seen", false)
|
||||||
decodedStringEquals(t, result, "[1]/mailbox", "good")
|
decodedStringEquals(t, result, "[1]/mailbox", "good")
|
||||||
decodedStringEquals(t, result, "[1]/id", "0002")
|
decodedStringEquals(t, result, "[1]/id", "0002")
|
||||||
decodedStringEquals(t, result, "[1]/from", "<from2@host>")
|
decodedStringEquals(t, result, "[1]/from", "<from2@host>")
|
||||||
@@ -122,6 +123,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
decodedStringEquals(t, result, "[1]/subject", "subject 2")
|
decodedStringEquals(t, result, "[1]/subject", "subject 2")
|
||||||
decodedStringEquals(t, result, "[1]/date", "2012-07-01T10:11:12.000000253-07:00")
|
decodedStringEquals(t, result, "[1]/date", "2012-07-01T10:11:12.000000253-07:00")
|
||||||
decodedNumberEquals(t, result, "[1]/size", 0)
|
decodedNumberEquals(t, result, "[1]/size", 0)
|
||||||
|
decodedBoolEquals(t, result, "[1]/seen", false)
|
||||||
|
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
// Wait for handler to finish logging
|
// Wait for handler to finish logging
|
||||||
@@ -183,6 +185,7 @@ func TestRestMessage(t *testing.T) {
|
|||||||
To: []*mail.Address{{Name: "", Address: "to1@host"}},
|
To: []*mail.Address{{Name: "", Address: "to1@host"}},
|
||||||
Subject: "subject 1",
|
Subject: "subject 1",
|
||||||
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, tzPST),
|
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, tzPST),
|
||||||
|
Seen: true,
|
||||||
},
|
},
|
||||||
&enmime.Envelope{
|
&enmime.Envelope{
|
||||||
Text: "This is some text",
|
Text: "This is some text",
|
||||||
@@ -221,6 +224,7 @@ func TestRestMessage(t *testing.T) {
|
|||||||
decodedStringEquals(t, result, "subject", "subject 1")
|
decodedStringEquals(t, result, "subject", "subject 1")
|
||||||
decodedStringEquals(t, result, "date", "2012-02-01T10:11:12.000000253-08:00")
|
decodedStringEquals(t, result, "date", "2012-02-01T10:11:12.000000253-08:00")
|
||||||
decodedNumberEquals(t, result, "size", 0)
|
decodedNumberEquals(t, result, "size", 0)
|
||||||
|
decodedBoolEquals(t, result, "seen", true)
|
||||||
decodedStringEquals(t, result, "body/text", "This is some text")
|
decodedStringEquals(t, result, "body/text", "This is some text")
|
||||||
decodedStringEquals(t, result, "body/html", "This is some HTML")
|
decodedStringEquals(t, result, "body/html", "This is some HTML")
|
||||||
decodedStringEquals(t, result, "header/To/[0]", "fred@fish.com")
|
decodedStringEquals(t, result, "header/To/[0]", "fred@fish.com")
|
||||||
@@ -234,3 +238,67 @@ func TestRestMessage(t *testing.T) {
|
|||||||
_, _ = io.Copy(os.Stderr, logbuf)
|
_, _ = io.Copy(os.Stderr, logbuf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRestMarkSeen(t *testing.T) {
|
||||||
|
mm := test.NewManager()
|
||||||
|
logbuf := setupWebServer(mm)
|
||||||
|
// Create some messages.
|
||||||
|
tzPDT := time.FixedZone("PDT", -7*3600)
|
||||||
|
tzPST := time.FixedZone("PST", -8*3600)
|
||||||
|
meta1 := message.Metadata{
|
||||||
|
Mailbox: "good",
|
||||||
|
ID: "0001",
|
||||||
|
From: &mail.Address{Name: "", Address: "from1@host"},
|
||||||
|
To: []*mail.Address{{Name: "", Address: "to1@host"}},
|
||||||
|
Subject: "subject 1",
|
||||||
|
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, tzPST),
|
||||||
|
}
|
||||||
|
meta2 := message.Metadata{
|
||||||
|
Mailbox: "good",
|
||||||
|
ID: "0002",
|
||||||
|
From: &mail.Address{Name: "", Address: "from2@host"},
|
||||||
|
To: []*mail.Address{{Name: "", Address: "to1@host"}},
|
||||||
|
Subject: "subject 2",
|
||||||
|
Date: time.Date(2012, 7, 1, 10, 11, 12, 253, tzPDT),
|
||||||
|
}
|
||||||
|
mm.AddMessage("good", &message.Message{Metadata: meta1})
|
||||||
|
mm.AddMessage("good", &message.Message{Metadata: meta2})
|
||||||
|
// Mark one read.
|
||||||
|
w, err := testRestPatch(baseURL+"/mailbox/good/0002", `{"seen":true}`)
|
||||||
|
expectCode := 200
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if w.Code != expectCode {
|
||||||
|
t.Fatalf("Expected code %v, got %v", expectCode, w.Code)
|
||||||
|
}
|
||||||
|
// Get mailbox.
|
||||||
|
w, err = testRestGet(baseURL + "/mailbox/good")
|
||||||
|
expectCode = 200
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if w.Code != expectCode {
|
||||||
|
t.Fatalf("Expected code %v, got %v", expectCode, w.Code)
|
||||||
|
}
|
||||||
|
// Check JSON.
|
||||||
|
dec := json.NewDecoder(w.Body)
|
||||||
|
var result []interface{}
|
||||||
|
if err := dec.Decode(&result); err != nil {
|
||||||
|
t.Errorf("Failed to decode JSON: %v", err)
|
||||||
|
}
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Fatalf("Expected 2 results, got %v", len(result))
|
||||||
|
}
|
||||||
|
decodedStringEquals(t, result, "[0]/id", "0001")
|
||||||
|
decodedBoolEquals(t, result, "[0]/seen", false)
|
||||||
|
decodedStringEquals(t, result, "[1]/id", "0002")
|
||||||
|
decodedBoolEquals(t, result, "[1]/seen", true)
|
||||||
|
|
||||||
|
if t.Failed() {
|
||||||
|
// Wait for handler to finish logging
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
// Dump buffered log data if there was a failure
|
||||||
|
_, _ = io.Copy(os.Stderr, logbuf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,10 +58,20 @@ func (c *Client) GetMessage(name, id string) (message *Message, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkSeen marks the specified message as having been read.
|
||||||
|
func (c *Client) MarkSeen(name, id string) error {
|
||||||
|
uri := "/api/v1/mailbox/" + url.QueryEscape(name) + "/" + id
|
||||||
|
err := c.doJSON("PATCH", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetMessageSource returns the message source given a mailbox name and message ID.
|
// GetMessageSource returns the message source given a mailbox name and message ID.
|
||||||
func (c *Client) GetMessageSource(name, id string) (*bytes.Buffer, error) {
|
func (c *Client) GetMessageSource(name, id string) (*bytes.Buffer, error) {
|
||||||
uri := "/api/v1/mailbox/" + url.QueryEscape(name) + "/" + id + "/source"
|
uri := "/api/v1/mailbox/" + url.QueryEscape(name) + "/" + id + "/source"
|
||||||
resp, err := c.do("GET", uri)
|
resp, err := c.do("GET", uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -81,7 +91,7 @@ func (c *Client) GetMessageSource(name, id string) (*bytes.Buffer, error) {
|
|||||||
// DeleteMessage deletes a single message given the mailbox name and message ID.
|
// DeleteMessage deletes a single message given the mailbox name and message ID.
|
||||||
func (c *Client) DeleteMessage(name, id string) error {
|
func (c *Client) DeleteMessage(name, id string) error {
|
||||||
uri := "/api/v1/mailbox/" + url.QueryEscape(name) + "/" + id
|
uri := "/api/v1/mailbox/" + url.QueryEscape(name) + "/" + id
|
||||||
resp, err := c.do("DELETE", uri)
|
resp, err := c.do("DELETE", uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -95,7 +105,7 @@ func (c *Client) DeleteMessage(name, id string) error {
|
|||||||
// PurgeMailbox deletes all messages in the given mailbox
|
// PurgeMailbox deletes all messages in the given mailbox
|
||||||
func (c *Client) PurgeMailbox(name string) error {
|
func (c *Client) PurgeMailbox(name string) error {
|
||||||
uri := "/api/v1/mailbox/" + url.QueryEscape(name)
|
uri := "/api/v1/mailbox/" + url.QueryEscape(name)
|
||||||
resp, err := c.do("DELETE", uri)
|
resp, err := c.do("DELETE", uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,32 @@ func TestClientV1GetMessage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClientV1MarkSeen(t *testing.T) {
|
||||||
|
var want, got string
|
||||||
|
|
||||||
|
c, err := New(baseURLStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
mth := &mockHTTPClient{}
|
||||||
|
c.client = mth
|
||||||
|
|
||||||
|
// Method under test
|
||||||
|
_ = c.MarkSeen("testbox", "20170107T224128-0000")
|
||||||
|
|
||||||
|
want = "PATCH"
|
||||||
|
got = mth.req.Method
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("req.Method == %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
want = baseURLStr + "/api/v1/mailbox/testbox/20170107T224128-0000"
|
||||||
|
got = mth.req.URL.String()
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("req.URL == %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestClientV1GetMessageSource(t *testing.T) {
|
func TestClientV1GetMessageSource(t *testing.T) {
|
||||||
var want, got string
|
var want, got string
|
||||||
|
|
||||||
@@ -158,7 +184,8 @@ func TestClientV1MessageHeader(t *testing.T) {
|
|||||||
"from":"from1",
|
"from":"from1",
|
||||||
"subject":"subject1",
|
"subject":"subject1",
|
||||||
"date":"2017-01-01T00:00:00.000-07:00",
|
"date":"2017-01-01T00:00:00.000-07:00",
|
||||||
"size":100
|
"size":100,
|
||||||
|
"seen":true
|
||||||
}
|
}
|
||||||
]`
|
]`
|
||||||
|
|
||||||
@@ -216,6 +243,12 @@ func TestClientV1MessageHeader(t *testing.T) {
|
|||||||
t.Errorf("Subject == %q, want %q", got, want)
|
t.Errorf("Subject == %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wantb := true
|
||||||
|
gotb := header.Seen
|
||||||
|
if gotb != wantb {
|
||||||
|
t.Errorf("Seen == %v, want %v", gotb, wantb)
|
||||||
|
}
|
||||||
|
|
||||||
// Test MessageHeader.Delete()
|
// Test MessageHeader.Delete()
|
||||||
mth.body = ""
|
mth.body = ""
|
||||||
err = header.Delete()
|
err = header.Delete()
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
@@ -18,28 +20,48 @@ type restClient struct {
|
|||||||
baseURL *url.URL
|
baseURL *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
// do performs an HTTP request with this client and returns the response
|
// do performs an HTTP request with this client and returns the response.
|
||||||
func (c *restClient) do(method, uri string) (*http.Response, error) {
|
func (c *restClient) do(method, uri string, body []byte) (*http.Response, error) {
|
||||||
rel, err := url.Parse(uri)
|
rel, err := url.Parse(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
url := c.baseURL.ResolveReference(rel)
|
url := c.baseURL.ResolveReference(rel)
|
||||||
|
var r io.Reader
|
||||||
// Build the request
|
if body != nil {
|
||||||
req, err := http.NewRequest(method, url.String(), nil)
|
r = bytes.NewReader(body)
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(method, url.String(), r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the request
|
|
||||||
return c.client.Do(req)
|
return c.client.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// doGet performs an HTTP request with this client and marshalls the JSON response into v
|
// doJSON performs an HTTP request with this client and marshalls the JSON response into v.
|
||||||
func (c *restClient) doJSON(method string, uri string, v interface{}) error {
|
func (c *restClient) doJSON(method string, uri string, v interface{}) error {
|
||||||
resp, err := c.do(method, uri)
|
resp, err := c.do(method, uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Decode response body
|
||||||
|
return json.NewDecoder(resp.Body).Decode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unexpected HTTP response status %v: %s", resp.StatusCode, resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// doJSONBody performs an HTTP request with this client and marshalls the JSON response into v.
|
||||||
|
func (c *restClient) doJSONBody(method string, uri string, body []byte, v interface{}) error {
|
||||||
|
resp, err := c.do(method, uri, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,17 +35,29 @@ func (m *mockHTTPClient) Do(req *http.Request) (resp *http.Response, err error)
|
|||||||
StatusCode: m.statusCode,
|
StatusCode: m.statusCode,
|
||||||
Body: ioutil.NopCloser(bytes.NewBufferString(m.body)),
|
Body: ioutil.NopCloser(bytes.NewBufferString(m.body)),
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockHTTPClient) ReqBody() []byte {
|
||||||
|
r, err := m.req.GetBody()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_ = r.Close()
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
func TestDo(t *testing.T) {
|
func TestDo(t *testing.T) {
|
||||||
var want, got string
|
var want, got string
|
||||||
|
|
||||||
mth := &mockHTTPClient{}
|
mth := &mockHTTPClient{}
|
||||||
c := &restClient{mth, baseURL}
|
c := &restClient{mth, baseURL}
|
||||||
|
body := []byte("Test body")
|
||||||
|
|
||||||
_, err := c.do("POST", "/dopost")
|
_, err := c.do("POST", "/dopost", body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -61,6 +73,11 @@ func TestDo(t *testing.T) {
|
|||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("req.URL == %q, want %q", got, want)
|
t.Errorf("req.URL == %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b := mth.ReqBody()
|
||||||
|
if !bytes.Equal(b, body) {
|
||||||
|
t.Errorf("req.Body == %q, want %q", b, body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoJSON(t *testing.T) {
|
func TestDoJSON(t *testing.T) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type JSONMessageHeaderV1 struct {
|
|||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Date time.Time `json:"date"`
|
Date time.Time `json:"date"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
|
Seen bool `json:"seen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONMessageV1 contains the same data as the header plus a JSONMessageBody
|
// JSONMessageV1 contains the same data as the header plus a JSONMessageBody
|
||||||
@@ -24,6 +25,7 @@ type JSONMessageV1 struct {
|
|||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Date time.Time `json:"date"`
|
Date time.Time `json:"date"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
|
Seen bool `json:"seen"`
|
||||||
Body *JSONMessageBodyV1 `json:"body"`
|
Body *JSONMessageBodyV1 `json:"body"`
|
||||||
Header map[string][]string `json:"header"`
|
Header map[string][]string `json:"header"`
|
||||||
Attachments []*JSONMessageAttachmentV1 `json:"attachments"`
|
Attachments []*JSONMessageAttachmentV1 `json:"attachments"`
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ func SetupRoutes(r *mux.Router) {
|
|||||||
web.Handler(MailboxPurgeV1)).Name("MailboxPurgeV1").Methods("DELETE")
|
web.Handler(MailboxPurgeV1)).Name("MailboxPurgeV1").Methods("DELETE")
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
||||||
web.Handler(MailboxShowV1)).Name("MailboxShowV1").Methods("GET")
|
web.Handler(MailboxShowV1)).Name("MailboxShowV1").Methods("GET")
|
||||||
|
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
||||||
|
web.Handler(MailboxMarkSeenV1)).Name("MailboxMarkSeenV1").Methods("PATCH")
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
||||||
web.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE")
|
web.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE")
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}/source").Handler(
|
r.Path("/api/v1/mailbox/{name}/{id}/source").Handler(
|
||||||
|
|||||||
@@ -21,7 +21,17 @@ func testRestGet(url string) (*httptest.ResponseRecorder, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
web.Router.ServeHTTP(w, req)
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRestPatch(url string, body string) (*httptest.ResponseRecorder, error) {
|
||||||
|
req, err := http.NewRequest("PATCH", url, strings.NewReader(body))
|
||||||
|
req.Header.Add("Accept", "application/json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
web.Router.ServeHTTP(w, req)
|
web.Router.ServeHTTP(w, req)
|
||||||
return w, nil
|
return w, nil
|
||||||
@@ -46,6 +56,22 @@ func setupWebServer(mm message.Manager) *bytes.Buffer {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodedBoolEquals(t *testing.T, json interface{}, path string, want bool) {
|
||||||
|
t.Helper()
|
||||||
|
els := strings.Split(path, "/")
|
||||||
|
val, msg := getDecodedPath(json, els...)
|
||||||
|
if msg != "" {
|
||||||
|
t.Errorf("JSON result%s", msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got, ok := val.(bool); ok {
|
||||||
|
if got == want {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Errorf("JSON result/%s == %v (%T), want: %v", path, val, val, want)
|
||||||
|
}
|
||||||
|
|
||||||
func decodedNumberEquals(t *testing.T, json interface{}, path string, want float64) {
|
func decodedNumberEquals(t *testing.T, json interface{}, path string, want float64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
els := strings.Split(path, "/")
|
els := strings.Split(path, "/")
|
||||||
|
|||||||
@@ -57,3 +57,17 @@ func (m *ManagerStub) GetMetadata(mailbox string) ([]*message.Metadata, error) {
|
|||||||
func (m *ManagerStub) MailboxForAddress(address string) (string, error) {
|
func (m *ManagerStub) MailboxForAddress(address string) (string, error) {
|
||||||
return policy.ParseMailboxName(address)
|
return policy.ParseMailboxName(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkSeen marks a message as having been read.
|
||||||
|
func (m *ManagerStub) MarkSeen(mailbox, id string) error {
|
||||||
|
if mailbox == "messageerr" {
|
||||||
|
return errors.New("internal error")
|
||||||
|
}
|
||||||
|
for _, msg := range m.mailboxes[mailbox] {
|
||||||
|
if msg.ID == id {
|
||||||
|
msg.Metadata.Seen = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return storage.ErrNotExist
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user