From 1e85699ccf513a6f148e35903038d66b895f3005 Mon Sep 17 00:00:00 2001 From: James Hillyerd Date: Mon, 14 Oct 2013 15:35:09 -0700 Subject: [PATCH] Add REST call for purging an entire mailbox --- etc/mailbox-purge.sh | 1 + smtpd/datastore.go | 1 + smtpd/filestore.go | 6 ++++++ smtpd/filestore_test.go | 41 +++++++++++++++++++++++++++++++++++++++ smtpd/retention_test.go | 5 +++++ web/mailbox_controller.go | 22 +++++++++++++++++++++ web/server.go | 1 + 7 files changed, 77 insertions(+) create mode 100755 etc/mailbox-purge.sh diff --git a/etc/mailbox-purge.sh b/etc/mailbox-purge.sh new file mode 100755 index 0000000..a8d3808 --- /dev/null +++ b/etc/mailbox-purge.sh @@ -0,0 +1 @@ +curl -i -H "Accept: application/json" --noproxy localhost -X DELETE http://localhost:9000/mailbox/$1 diff --git a/smtpd/datastore.go b/smtpd/datastore.go index 7ae989d..039fd97 100644 --- a/smtpd/datastore.go +++ b/smtpd/datastore.go @@ -15,6 +15,7 @@ type DataStore interface { type Mailbox interface { GetMessages() ([]Message, error) GetMessage(id string) (Message, error) + Purge() error NewMessage() Message String() string } diff --git a/smtpd/filestore.go b/smtpd/filestore.go index 4368de5..736fcf4 100644 --- a/smtpd/filestore.go +++ b/smtpd/filestore.go @@ -178,6 +178,12 @@ func (mb *FileMailbox) GetMessage(id string) (Message, error) { return nil, fmt.Errorf("Message %s not in index", id) } +// Delete all messages in this mailbox +func (mb *FileMailbox) Purge() error { + mb.messages = mb.messages[:0] + return mb.writeIndex() +} + // readIndex loads the mailbox index data from disk func (mb *FileMailbox) readIndex() error { // Clear message slice, open index diff --git a/smtpd/filestore_test.go b/smtpd/filestore_test.go index 85f7fae..1a0388c 100644 --- a/smtpd/filestore_test.go +++ b/smtpd/filestore_test.go @@ -218,6 +218,47 @@ func TestFSDelete(t *testing.T) { } +// Test purging a mailbox +func TestFSPurge(t *testing.T) { + ds := setupDataStore() + defer teardownDataStore(ds) + + mbName := "fred" + subjects := []string{"alpha", "bravo", "charlie", "delta", "echo"} + + for _, subj := range subjects { + // Add a message + deliverMessage(ds, mbName, subj, time.Now()) + } + + mb, err := ds.MailboxFor(mbName) + if err != nil { + panic(err) + } + msgs, err := mb.GetMessages() + if err != nil { + panic(err) + } + assert.Equal(t, len(subjects), len(msgs), "Expected %v message(s), but got %v", + len(subjects), len(msgs)) + + // Purge mailbox + err = mb.Purge() + assert.Nil(t, err) + + // Confirm deletion + mb, err = ds.MailboxFor(mbName) + if err != nil { + panic(err) + } + msgs, err = mb.GetMessages() + if err != nil { + panic(err) + } + + assert.Equal(t, len(msgs), 0, "Expected mailbox to have zero messages, got %v", len(msgs)) +} + // Test message size calculation func TestFSSize(t *testing.T) { ds := setupDataStore() diff --git a/smtpd/retention_test.go b/smtpd/retention_test.go index 2841243..9aa09f2 100644 --- a/smtpd/retention_test.go +++ b/smtpd/retention_test.go @@ -92,6 +92,11 @@ func (m *MockMailbox) GetMessage(id string) (Message, error) { return args.Get(0).(Message), args.Error(1) } +func (m *MockMailbox) Purge() error { + args := m.Called() + return args.Error(0) +} + func (m *MockMailbox) NewMessage() Message { args := m.Called() return args.Get(0).(Message) diff --git a/web/mailbox_controller.go b/web/mailbox_controller.go index 1d4711b..807e2eb 100644 --- a/web/mailbox_controller.go +++ b/web/mailbox_controller.go @@ -94,6 +94,28 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *Context) (err er }) } +func MailboxPurge(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) { + // Don't have to validate these aren't empty, Gorilla returns 404 + name := ctx.Vars["name"] + + mb, err := ctx.DataStore.MailboxFor(name) + if err != nil { + return fmt.Errorf("MailboxFor('%v'): %v", name, err) + } + if err := mb.Purge(); err != nil { + return fmt.Errorf("Mailbox(%q) Purge: %v", name, err) + } + log.LogTrace("Purged mailbox for %q", name) + + if ctx.IsJson { + return RenderJson(w, "OK") + } + + w.Header().Set("Content-Type", "text/plain") + io.WriteString(w, "OK") + return nil +} + func MailboxHtml(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) { // Don't have to validate these aren't empty, Gorilla returns 404 name := ctx.Vars["name"] diff --git a/web/server.go b/web/server.go index fcffdce..63a022e 100644 --- a/web/server.go +++ b/web/server.go @@ -36,6 +36,7 @@ func setupRoutes(cfg config.WebConfig) { r.Path("/status").Handler(handler(RootStatus)).Name("RootStatus").Methods("GET") r.Path("/mailbox").Handler(handler(MailboxIndex)).Name("MailboxIndex").Methods("GET") r.Path("/mailbox/{name}").Handler(handler(MailboxList)).Name("MailboxList").Methods("GET") + r.Path("/mailbox/{name}").Handler(handler(MailboxPurge)).Name("MailboxPurge").Methods("DELETE") r.Path("/mailbox/{name}/{id}").Handler(handler(MailboxShow)).Name("MailboxShow").Methods("GET") r.Path("/mailbox/{name}/{id}/html").Handler(handler(MailboxHtml)).Name("MailboxHtml").Methods("GET") r.Path("/mailbox/{name}/{id}/source").Handler(handler(MailboxSource)).Name("MailboxSource").Methods("GET")