processing inbox
This commit is contained in:
parent
1d69a1fbce
commit
e1758db30e
|
@ -0,0 +1,83 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.sr.ht/~ewintr/gte/internal/task"
|
||||
"git.sr.ht/~ewintr/gte/pkg/mstore"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config := &mstore.EmailConfiguration{
|
||||
IMAPURL: os.Getenv("IMAP_URL"),
|
||||
IMAPUsername: os.Getenv("IMAP_USERNAME"),
|
||||
IMAPPassword: os.Getenv("IMAP_PASSWORD"),
|
||||
}
|
||||
if !config.Valid() {
|
||||
log.Fatal("please set MAIL_USER, MAIL_PASSWORD, etc environment variables")
|
||||
}
|
||||
|
||||
mailStore, err := mstore.EmailConnect(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer mailStore.Disconnect()
|
||||
|
||||
taskRepo := task.NewRepository(mailStore)
|
||||
tasks, err := taskRepo.FindAll("INBOX")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, t := range tasks {
|
||||
fmt.Printf("processing: %s... ", t.Action)
|
||||
|
||||
if t.Dirty() {
|
||||
if err := taskRepo.Update(t); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("updated.")
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
/*
|
||||
folders, err := mailStore.FolderNames()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, f := range folders {
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
if err := mailStore.Select("Today"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
messages, err := mailStore.Messages()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, m := range messages {
|
||||
fmt.Printf("%d: %s\n", m.Uid, m.Subject)
|
||||
}
|
||||
if len(messages) == 0 {
|
||||
log.Fatal("no messages")
|
||||
return
|
||||
}
|
||||
|
||||
if err := mailStore.Remove(messages[0].Uid); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body := NewBody(`From: todo <process@erikwinter.nl>
|
||||
Subject: the subject
|
||||
|
||||
And here comes the body`)
|
||||
|
||||
if err := mailStore.Append("INBOX", imap.Literal(body)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.sr.ht/~ewintr/gte/pkg/mstore"
|
||||
)
|
||||
|
||||
type Body struct {
|
||||
reader io.Reader
|
||||
length int
|
||||
}
|
||||
|
||||
func NewBody(msg string) *Body {
|
||||
return &Body{
|
||||
reader: strings.NewReader(msg),
|
||||
length: len([]byte(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Body) Read(p []byte) (int, error) {
|
||||
return b.reader.Read(p)
|
||||
}
|
||||
|
||||
func (b *Body) Len() int {
|
||||
return b.length
|
||||
}
|
||||
|
||||
func main() {
|
||||
config := &mstore.EmailConfiguration{
|
||||
IMAPURL: os.Getenv("IMAP_URL"),
|
||||
IMAPUsername: os.Getenv("IMAP_USERNAME"),
|
||||
IMAPPassword: os.Getenv("IMAP_PASSWORD"),
|
||||
}
|
||||
if !config.Valid() {
|
||||
fmt.Printf("conf: %v\n", config)
|
||||
log.Fatal("please set MAIL_USER, MAIL_PASSWORD, etc environment variables")
|
||||
}
|
||||
//fmt.Printf("conf: %+v\n", config)
|
||||
|
||||
mailStore, err := mstore.EmailConnect(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer mailStore.Disconnect()
|
||||
|
||||
/*
|
||||
folders, err := mailStore.FolderNames()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, f := range folders {
|
||||
fmt.Println(f)
|
||||
}
|
||||
*/
|
||||
|
||||
if err := mailStore.Select("Today"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
messages, err := mailStore.Messages()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, m := range messages {
|
||||
fmt.Printf("%d: %s\n", m.Uid, m.Subject)
|
||||
}
|
||||
if len(messages) == 0 {
|
||||
log.Fatal("no messages")
|
||||
return
|
||||
}
|
||||
|
||||
if err := mailStore.Remove(messages[0].Uid); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/*
|
||||
body := NewBody(`From: todo <process@erikwinter.nl>
|
||||
Subject: the subject
|
||||
|
||||
And here comes the body`)
|
||||
|
||||
if err := mailStore.Append("INBOX", imap.Literal(body)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
*/
|
||||
}
|
4
go.mod
4
go.mod
|
@ -5,6 +5,6 @@ go 1.14
|
|||
require (
|
||||
git.sr.ht/~ewintr/go-kit v0.0.0-20201229104230-4d7958f8de04
|
||||
github.com/emersion/go-imap v1.0.6
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
||||
github.com/emersion/go-smtp v0.14.0
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
|
||||
github.com/google/uuid v1.2.0
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -53,8 +53,6 @@ github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b h1:uhWtEWBHgop1rq
|
|||
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/emersion/go-smtp v0.14.0 h1:RYW203p+EcPjL8Z/ZpT9lZ6iOc8MG1MQzEx1UKEkXlA=
|
||||
github.com/emersion/go-smtp v0.14.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
@ -92,6 +90,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
|
|
|
@ -2,21 +2,9 @@ package task
|
|||
|
||||
import "time"
|
||||
|
||||
type Date time.Time
|
||||
|
||||
func (d *Date) Weekday() Weekday {
|
||||
return d.Weekday()
|
||||
}
|
||||
|
||||
type Weekday time.Weekday
|
||||
|
||||
type Period int
|
||||
|
||||
type Task struct {
|
||||
Action string
|
||||
Due Date
|
||||
}
|
||||
|
||||
type Recurrer interface {
|
||||
FirstAfter(date Date) Date
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.sr.ht/~ewintr/gte/pkg/mstore"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMStoreError = errors.New("mstore gave error response")
|
||||
)
|
||||
|
||||
type TaskRepo struct {
|
||||
mstore mstore.MStorer
|
||||
}
|
||||
|
||||
func NewRepository(ms mstore.MStorer) *TaskRepo {
|
||||
return &TaskRepo{
|
||||
mstore: ms,
|
||||
}
|
||||
}
|
||||
|
||||
func (tr *TaskRepo) FindAll(folder string) ([]*Task, error) {
|
||||
msgs, err := tr.mstore.Messages(folder)
|
||||
if err != nil {
|
||||
return []*Task{}, err
|
||||
}
|
||||
|
||||
tasks := []*Task{}
|
||||
for _, msg := range msgs {
|
||||
if msg.Valid() {
|
||||
tasks = append(tasks, NewFromMessage(msg))
|
||||
}
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func (tr *TaskRepo) Update(t *Task) error {
|
||||
if !t.Current {
|
||||
return ErrOutdatedTask
|
||||
}
|
||||
if !t.Dirty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// add new
|
||||
if err := tr.mstore.Add(t.Folder, t.Subject(), t.Body()); err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrMStoreError, err)
|
||||
}
|
||||
|
||||
// remove old
|
||||
if err := tr.mstore.Remove(t.Message); err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrMStoreError, err)
|
||||
}
|
||||
|
||||
t.Current = false
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package task
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.sr.ht/~ewintr/gte/pkg/mstore"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOutdatedTask = errors.New("task is outdated")
|
||||
)
|
||||
|
||||
type Date time.Time
|
||||
|
||||
func (d *Date) Weekday() Weekday {
|
||||
return d.Weekday()
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
Id string
|
||||
Folder string
|
||||
Action string
|
||||
Due Date
|
||||
Message *mstore.Message
|
||||
Current bool
|
||||
Simplified bool
|
||||
}
|
||||
|
||||
func NewFromMessage(msg *mstore.Message) *Task {
|
||||
fmt.Println(msg.Subject)
|
||||
id := FieldFromBody("id", msg.Body)
|
||||
if id == "" {
|
||||
id = uuid.New().String()
|
||||
}
|
||||
|
||||
action := FieldFromBody("action", msg.Body)
|
||||
if action == "" {
|
||||
action = FieldFromSubject("action", msg.Subject)
|
||||
}
|
||||
|
||||
folder := msg.Folder
|
||||
if folder == "INBOX" {
|
||||
folder = "New"
|
||||
}
|
||||
|
||||
return &Task{
|
||||
Id: id,
|
||||
Action: action,
|
||||
Folder: folder,
|
||||
Message: msg,
|
||||
Current: true,
|
||||
Simplified: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Dirty checks if the task has unsaved changes
|
||||
func (t *Task) Dirty() bool {
|
||||
mBody := t.Message.Body
|
||||
mSubject := t.Message.Subject
|
||||
|
||||
if t.Id != FieldFromBody("id", mBody) {
|
||||
return true
|
||||
}
|
||||
|
||||
if t.Folder != t.Message.Folder {
|
||||
return true
|
||||
}
|
||||
|
||||
if t.Action != FieldFromBody("action", mBody) {
|
||||
return true
|
||||
}
|
||||
if t.Action != FieldFromSubject("action", mSubject) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Task) Subject() string {
|
||||
return t.Action
|
||||
}
|
||||
|
||||
func (t *Task) Body() string {
|
||||
body := fmt.Sprintf("id: %s\n", t.Id)
|
||||
body += fmt.Sprintf("action: %s\n", t.Action)
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func FieldFromBody(field, body string) string {
|
||||
lines := strings.Split(body, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(parts[0]) == field {
|
||||
return strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func FieldFromSubject(field, subject string) string {
|
||||
if field == "action" {
|
||||
return strings.ToLower(subject)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
|
@ -2,12 +2,35 @@ package mstore
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
)
|
||||
|
||||
type Body struct {
|
||||
reader io.Reader
|
||||
length int
|
||||
}
|
||||
|
||||
func NewBody(msg string) *Body {
|
||||
|
||||
return &Body{
|
||||
reader: strings.NewReader(msg),
|
||||
length: len([]byte(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Body) Read(p []byte) (int, error) {
|
||||
return b.reader.Read(p)
|
||||
}
|
||||
|
||||
func (b *Body) Len() int {
|
||||
return b.length
|
||||
}
|
||||
|
||||
type EmailConfiguration struct {
|
||||
IMAPURL string
|
||||
IMAPUsername string
|
||||
|
@ -48,7 +71,7 @@ func (es *Email) Disconnect() {
|
|||
es.imap.Logout()
|
||||
}
|
||||
|
||||
func (es *Email) FolderNames() ([]string, error) {
|
||||
func (es *Email) Folders() ([]string, error) {
|
||||
boxes, done := make(chan *imap.MailboxInfo), make(chan error)
|
||||
go func() {
|
||||
done <- es.imap.List("", "*", boxes)
|
||||
|
@ -66,21 +89,20 @@ func (es *Email) FolderNames() ([]string, error) {
|
|||
return folders, nil
|
||||
}
|
||||
|
||||
func (es *Email) Select(folder string) error {
|
||||
func (es *Email) selectFolder(folder string) error {
|
||||
status, err := es.imap.Select(folder, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("status: %+v\n", status)
|
||||
|
||||
es.mboxStatus = status
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Email) Messages() ([]*Message, error) {
|
||||
if es.mboxStatus == nil {
|
||||
return []*Message{}, fmt.Errorf("no mailbox selected")
|
||||
func (es *Email) Messages(folder string) ([]*Message, error) {
|
||||
if err := es.selectFolder(folder); err != nil {
|
||||
return []*Message{}, err
|
||||
}
|
||||
|
||||
if es.mboxStatus.Messages == 0 {
|
||||
|
@ -97,9 +119,9 @@ func (es *Email) Messages() ([]*Message, error) {
|
|||
|
||||
messages := []*Message{}
|
||||
for m := range imsg {
|
||||
//fmt.Printf("%+v\n", m)
|
||||
messages = append(messages, &Message{
|
||||
Uid: m.Uid,
|
||||
Folder: folder,
|
||||
Subject: m.Envelope.Subject,
|
||||
})
|
||||
}
|
||||
|
@ -111,21 +133,29 @@ func (es *Email) Messages() ([]*Message, error) {
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (es *Email) Append(mbox string, msg imap.Literal) error {
|
||||
return es.imap.Append(mbox, nil, time.Time{}, msg)
|
||||
func (es *Email) Add(folder, subject, body string) error {
|
||||
msgStr := fmt.Sprintf(`From: todo <process@erikwinter.nl>
|
||||
Subject: %s
|
||||
|
||||
%s`, subject, body)
|
||||
|
||||
msg := NewBody(msgStr)
|
||||
|
||||
return es.imap.Append(folder, nil, time.Time{}, imap.Literal(msg))
|
||||
}
|
||||
|
||||
func (es *Email) Remove(uid uint32) error {
|
||||
if uid == 0 {
|
||||
return fmt.Errorf("invalid uid: %d", uid)
|
||||
func (es *Email) Remove(msg *Message) error {
|
||||
if !msg.Valid() {
|
||||
return ErrInvalidMessage
|
||||
}
|
||||
if es.mboxStatus == nil {
|
||||
return fmt.Errorf("no mailbox selected")
|
||||
|
||||
if err := es.selectFolder(msg.Folder); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set deleted flag
|
||||
seqset := new(imap.SeqSet)
|
||||
seqset.AddRange(uid, uid)
|
||||
seqset.AddRange(msg.Uid, msg.Uid)
|
||||
storeItem := imap.FormatFlagsOp(imap.SetFlags, true)
|
||||
err := es.imap.UidStore(seqset, storeItem, imap.FormatStringList([]string{imap.DeletedFlag}), nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -37,7 +37,7 @@ func NewMemory(folders []string) (*Memory, error) {
|
|||
|
||||
func (mem *Memory) Folders() ([]string, error) {
|
||||
folders := []string{}
|
||||
for f, _ := range mem.messages {
|
||||
for f := range mem.messages {
|
||||
folders = append(folders, f)
|
||||
}
|
||||
|
||||
|
@ -56,15 +56,15 @@ func (mem *Memory) Select(folder string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (mem *Memory) Add(subject, body string) error {
|
||||
func (mem *Memory) Add(folder, subject, body string) error {
|
||||
if subject == "" {
|
||||
return ErrInvalidMessage
|
||||
}
|
||||
if mem.Selected == "" {
|
||||
return ErrNoFolderSelected
|
||||
if _, ok := mem.messages[folder]; !ok {
|
||||
return ErrFolderDoesNotExist
|
||||
}
|
||||
|
||||
mem.messages[mem.Selected] = append(mem.messages[mem.Selected], &Message{
|
||||
mem.messages[folder] = append(mem.messages[folder], &Message{
|
||||
Uid: mem.nextUid,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
|
|
|
@ -101,12 +101,6 @@ func TestMemorySelect(t *testing.T) {
|
|||
func TestMemoryAdd(t *testing.T) {
|
||||
folder := "folder"
|
||||
|
||||
t.Run("no folder selected", func(t *testing.T) {
|
||||
mem, err := mstore.NewMemory([]string{folder})
|
||||
test.OK(t, err)
|
||||
test.Equals(t, mstore.ErrNoFolderSelected, mem.Add("subject", ""))
|
||||
})
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
subject string
|
||||
|
@ -124,8 +118,7 @@ func TestMemoryAdd(t *testing.T) {
|
|||
t.Run(tc.name, func(t *testing.T) {
|
||||
mem, err := mstore.NewMemory([]string{folder})
|
||||
test.OK(t, err)
|
||||
mem.Select(folder)
|
||||
test.Equals(t, tc.exp, mem.Add(tc.subject, ""))
|
||||
test.Equals(t, tc.exp, mem.Add(folder, tc.subject, ""))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +161,6 @@ func TestMemoryMessages(t *testing.T) {
|
|||
test.OK(t, err)
|
||||
|
||||
expMessages := []*mstore.Message{}
|
||||
test.OK(t, mem.Select(folderA))
|
||||
for i := 1; i <= tc.amount; i++ {
|
||||
m := &mstore.Message{
|
||||
Uid: uint32(i),
|
||||
|
@ -178,7 +170,7 @@ func TestMemoryMessages(t *testing.T) {
|
|||
if tc.folder == folderA {
|
||||
expMessages = append(expMessages, m)
|
||||
}
|
||||
test.OK(t, mem.Add(m.Subject, m.Body))
|
||||
test.OK(t, mem.Add(folderA, m.Subject, m.Body))
|
||||
}
|
||||
|
||||
test.OK(t, mem.Select(tc.folder))
|
||||
|
@ -200,9 +192,8 @@ func TestMemoryRemove(t *testing.T) {
|
|||
|
||||
mem, err := mstore.NewMemory([]string{folderA, folderB})
|
||||
test.OK(t, err)
|
||||
test.OK(t, mem.Select(folderA))
|
||||
for i := 1; i <= 3; i++ {
|
||||
test.OK(t, mem.Add(fmt.Sprintf("subject-%d", i), ""))
|
||||
test.OK(t, mem.Add(folderA, fmt.Sprintf("subject-%d", i), ""))
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
|
|
|
@ -12,18 +12,18 @@ var (
|
|||
|
||||
type Message struct {
|
||||
Uid uint32
|
||||
Folder string
|
||||
Subject string
|
||||
Body string
|
||||
}
|
||||
|
||||
func (m *Message) Valid() bool {
|
||||
return m.Uid != 0 && m.Subject != ""
|
||||
return m.Uid != 0 && m.Subject != "" && m.Folder != ""
|
||||
}
|
||||
|
||||
type MStorer interface {
|
||||
Folders() ([]string, error)
|
||||
Select(folder string) error
|
||||
Messages() ([]*Message, error)
|
||||
Add(message *Message) error
|
||||
Remove(uid uint32) error
|
||||
Messages(folder string) ([]*Message, error)
|
||||
Add(folder, subject, body string) error
|
||||
Remove(msg *Message) error
|
||||
}
|
||||
|
|
|
@ -19,20 +19,45 @@ func TestMessageValid(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "no uid",
|
||||
message: &mstore.Message{Subject: "subject", Body: "body"},
|
||||
message: &mstore.Message{
|
||||
Subject: "subject",
|
||||
Folder: "folder",
|
||||
Body: "body",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no folder",
|
||||
message: &mstore.Message{
|
||||
Uid: 1,
|
||||
Subject: "subject",
|
||||
Body: "body",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no subject",
|
||||
message: &mstore.Message{Uid: 1, Body: "body"},
|
||||
message: &mstore.Message{
|
||||
Uid: 1,
|
||||
Folder: "folder",
|
||||
Body: "body",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no body",
|
||||
message: &mstore.Message{Uid: 1, Subject: "subject"},
|
||||
message: &mstore.Message{
|
||||
Uid: 1,
|
||||
Folder: "folder",
|
||||
Subject: "subject",
|
||||
},
|
||||
exp: true,
|
||||
},
|
||||
{
|
||||
name: "all present",
|
||||
message: &mstore.Message{Uid: 1, Subject: "subject", Body: "body"},
|
||||
message: &mstore.Message{
|
||||
Uid: 1,
|
||||
Folder: "folder",
|
||||
Subject: "subject",
|
||||
Body: "body",
|
||||
},
|
||||
exp: true,
|
||||
},
|
||||
} {
|
||||
|
|
Loading…
Reference in New Issue