diff --git a/app/attachment_get.go b/app/attachment.go
similarity index 100%
rename from app/attachment_get.go
rename to app/attachment.go
diff --git a/app/message_handle.go b/app/message_handle.go
index 2222a143..5c78a0b6 100644
--- a/app/message_handle.go
+++ b/app/message_handle.go
@@ -7,5 +7,11 @@ type MessageSendRequest struct {
}
func (a *App) MessageSend(req *MessageSendRequest) error {
- return a.endpointSVC.SendBridges(req.Message, a.bridgeSVC.GetBridges(req.Message))
+ err := a.endpointSVC.SendBridges(req.Message, a.bridgeSVC.GetBridges(req.Message))
+ if err != nil {
+ a.messageSVC.UpdateStatus(req.Message, domain.StatusFailed)
+ return err
+ }
+
+ return a.messageSVC.UpdateStatus(req.Message, domain.StatusSent)
}
diff --git a/app/message_list.go b/app/message_list.go
index b9848078..d3bc2e0d 100644
--- a/app/message_list.go
+++ b/app/message_list.go
@@ -1,12 +1,52 @@
package app
-import "github.com/ItsNotGoodName/smtpbridge/domain"
+import (
+ "path"
+
+ "github.com/ItsNotGoodName/smtpbridge/dto"
+)
type MessageListRequest struct {
- Limit int
- Offset int
+ Page int
+ AttachmentPath string
}
-func (a *App) MessageList(req *MessageListRequest) ([]domain.Message, error) {
- return a.messageSVC.List(req.Limit, req.Offset)
+func (a *App) MessageList(req *MessageListRequest) ([]dto.Message, error) {
+ if req.Page < 0 {
+ req.Page = 0
+ }
+
+ msgs, err := a.messageSVC.List(10, req.Page*10)
+ if err != nil {
+ return nil, err
+ }
+
+ var result []dto.Message
+ for _, msg := range msgs {
+ var attachments []dto.Attachment
+ for _, attachment := range msg.Attachments {
+ attachments = append(attachments, dto.Attachment{
+ UUID: attachment.UUID,
+ Name: attachment.Name,
+ Path: path.Join(req.AttachmentPath, a.dao.Attachment.GetAttachmentFile(&attachment)),
+ })
+ }
+
+ var to []string
+ for toAddr := range msg.To {
+ to = append(to, toAddr)
+ }
+
+ result = append(result, dto.Message{
+ UUID: msg.UUID,
+ From: msg.From,
+ To: to,
+ Status: msg.Status.String(),
+ Subject: msg.Subject,
+ Text: msg.Text,
+ Attachments: attachments,
+ })
+ }
+
+ return result, nil
}
diff --git a/domain/message.go b/domain/message.go
index 35045061..7f7721e3 100644
--- a/domain/message.go
+++ b/domain/message.go
@@ -25,6 +25,16 @@ const (
StatusFailed
)
+var status []string = []string{
+ "created",
+ "sent",
+ "failed",
+}
+
+func (s Status) String() string {
+ return status[s]
+}
+
func NewMessage(subject, from string, to map[string]bool, text string) *Message {
return &Message{
CreatedAt: time.Now(),
diff --git a/dto/dto.go b/dto/dto.go
new file mode 100644
index 00000000..9e671589
--- /dev/null
+++ b/dto/dto.go
@@ -0,0 +1,17 @@
+package dto
+
+type Message struct {
+ UUID string `json:"uuid"`
+ Status string `json:"status"`
+ From string `json:"from"`
+ To []string `json:"to"`
+ Subject string `json:"subject"`
+ Text string `json:"text"`
+ Attachments []Attachment `json:"attachments"`
+}
+
+type Attachment struct {
+ UUID string `json:"uuid"`
+ Name string `json:"name"`
+ Path string `json:"path"`
+}
diff --git a/left/router/handlers.go b/left/router/handlers.go
index 7f92ac65..d0a75b0c 100644
--- a/left/router/handlers.go
+++ b/left/router/handlers.go
@@ -7,12 +7,12 @@ import (
"net/http"
"github.com/ItsNotGoodName/smtpbridge/app"
- "github.com/ItsNotGoodName/smtpbridge/domain"
+ "github.com/ItsNotGoodName/smtpbridge/dto"
)
-func (s *Router) GetAttachments(prefix string) http.HandlerFunc {
+func (s *Router) GetAttachments() http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
- http.StripPrefix(prefix, http.FileServer(http.FS(s.a.AttachmentGetFS()))).ServeHTTP(rw, r)
+ http.StripPrefix(s.attachmentURI, http.FileServer(http.FS(s.a.AttachmentGetFS()))).ServeHTTP(rw, r)
}
}
@@ -21,7 +21,7 @@ var templateFS embed.FS
func (s *Router) GetIndex() http.HandlerFunc {
type Data struct {
- Messages []domain.Message
+ Messages []dto.Message
}
index, err := template.ParseFS(templateFS, "template/index.html")
@@ -30,12 +30,17 @@ func (s *Router) GetIndex() http.HandlerFunc {
}
return func(rw http.ResponseWriter, r *http.Request) {
- messages, err := s.a.MessageList(&app.MessageListRequest{Limit: 10, Offset: 0})
+ messages, err := s.a.MessageList(&app.MessageListRequest{AttachmentPath: s.attachmentURI, Page: 0})
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
- index.Execute(rw, Data{Messages: messages})
+ log.Println("router.Router.GetIndex:", len(messages), "messages")
+ err = index.Execute(rw, Data{Messages: messages})
+ if err != nil {
+ http.Error(rw, err.Error(), http.StatusInternalServerError)
+ return
+ }
}
}
diff --git a/left/router/route.go b/left/router/route.go
index f774ac29..c229a646 100644
--- a/left/router/route.go
+++ b/left/router/route.go
@@ -1,6 +1,6 @@
package router
func (s *Router) route() {
- s.r.Get("/attachments/*", s.GetAttachments("/attachments/"))
+ s.r.Get(s.attachmentURI+"*", s.GetAttachments())
s.r.Get("/", s.GetIndex())
}
diff --git a/left/router/router.go b/left/router/router.go
index 62d760ae..72134303 100644
--- a/left/router/router.go
+++ b/left/router/router.go
@@ -11,14 +11,16 @@ import (
)
type Router struct {
- r *chi.Mux
- a *app.App
+ r *chi.Mux
+ a *app.App
+ attachmentURI string
}
func New(app *app.App) *Router {
s := Router{
- r: chi.NewRouter(),
- a: app,
+ r: chi.NewRouter(),
+ a: app,
+ attachmentURI: "/attachments/",
}
// A good base middleware stack
diff --git a/left/router/template/index.html b/left/router/template/index.html
index 0b678290..5bcadd04 100644
--- a/left/router/template/index.html
+++ b/left/router/template/index.html
@@ -16,7 +16,7 @@
{{ $msg.Subject }}
{{ else }}
No Subject
{{ end }}
- Status: {{ $msg.Status }}
+ {{ $msg.Status }}
{{ $msg.Text }}
@@ -26,8 +26,8 @@ No Subject
{{ range $att := $msg.Attachments }}
{{ end }}
diff --git a/right/database/attachment.go b/right/database/attachment.go
new file mode 100644
index 00000000..2e1511c3
--- /dev/null
+++ b/right/database/attachment.go
@@ -0,0 +1,66 @@
+package database
+
+import (
+ "fmt"
+ "io/fs"
+ "os"
+ "path"
+
+ "github.com/ItsNotGoodName/smtpbridge/domain"
+ "github.com/asdine/storm"
+ "github.com/asdine/storm/q"
+)
+
+func (db *DB) CreateAttachment(att *domain.Attachment) error {
+ err := db.db.Save(att)
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(db.getAttachmentPath(att), att.Data, 0644)
+}
+
+// getAttachmentPath returns the path to the attachment file on the file system.
+func (db *DB) getAttachmentPath(att *domain.Attachment) string {
+ return path.Join(db.attDir, db.GetAttachmentFile(att))
+}
+
+func (db *DB) GetAttachmentFile(att *domain.Attachment) string {
+ return fmt.Sprintf("%s.%s", att.UUID, att.Type)
+}
+
+func (db *DB) GetAttachmentFS() fs.FS {
+ return db.fs
+}
+
+func (db *DB) GetAttachment(uuid string) (*domain.Attachment, error) {
+ var att domain.Attachment
+ err := db.db.One("UUID", uuid, att)
+ if err != nil {
+ return nil, err
+ }
+
+ return &att, nil
+}
+
+func (db *DB) GetAttachmentData(att *domain.Attachment) ([]byte, error) {
+ data, err := os.ReadFile(db.getAttachmentPath(att))
+ if err != nil {
+ return nil, err
+ }
+
+ return data, nil
+}
+
+func (db *DB) GetAttachments(msg *domain.Message) ([]domain.Attachment, error) {
+ var atts []domain.Attachment
+ err := db.db.Select(q.Eq("MessageUUID", msg.UUID)).Find(&atts)
+ if err != nil {
+ if err == storm.ErrNotFound {
+ return []domain.Attachment{}, nil
+ }
+ return nil, err
+ }
+
+ return atts, nil
+}
diff --git a/right/database/database.go b/right/database/database.go
index 97576b4f..4cdd2061 100644
--- a/right/database/database.go
+++ b/right/database/database.go
@@ -1,20 +1,17 @@
package database
import (
- "fmt"
"io/fs"
"log"
"os"
- "path"
- "github.com/ItsNotGoodName/smtpbridge/domain"
"github.com/asdine/storm"
- "github.com/asdine/storm/q"
)
type DB struct {
db *storm.DB
attDir string
+ fs fs.FS
}
func NewDB(dbFile, attDir string) *DB {
@@ -30,151 +27,7 @@ func NewDB(dbFile, attDir string) *DB {
return &DB{
db: db,
+ fs: os.DirFS(attDir),
attDir: attDir,
}
}
-
-func (db *DB) CreateMessage(msg *domain.Message) error {
- return db.db.Save(msg)
-}
-
-func (db *DB) GetMessage(uuid string) (*domain.Message, error) {
- var msg domain.Message
- err := db.db.One("UUID", uuid, msg)
- if err != nil {
- return nil, err
- }
-
- return &msg, nil
-}
-
-func (db *DB) UpdateMessage(msg *domain.Message, updateFN func(msg *domain.Message) (*domain.Message, error)) error {
- tx, err := db.db.Begin(true)
- if err != nil {
- return err
- }
- defer tx.Rollback()
-
- var existingMSG domain.Message
- if err := tx.One("UUID", msg.UUID, &existingMSG); err != nil {
- return err
- }
-
- updatedMSG, err := updateFN(&existingMSG)
- if err != nil {
- return err
- }
-
- err = tx.Save(updatedMSG)
- if err != nil {
- return err
- }
-
- return tx.Commit()
-}
-
-func (db *DB) GetMessages(limit, offset int) ([]domain.Message, error) {
- var msgs []domain.Message
- err := db.db.Select().OrderBy("CreatedAt").Limit(limit).Skip(offset).Reverse().Find(&msgs)
- if err != nil && err != storm.ErrNotFound {
- return nil, err
- }
-
- return msgs, nil
-}
-
-func (db *DB) DeleteMessage(msg *domain.Message) error {
- tx, err := db.db.Begin(true)
- if err != nil {
- return err
- }
- defer tx.Rollback()
-
- query := tx.Select(q.Eq("MessageUUID", msg.UUID))
-
- // List attachments
- var atts []domain.Attachment
- err = query.Find(&atts)
- if err != storm.ErrNotFound {
- if err != nil {
- return err
- }
-
- // Delete attachments
- err = query.Delete(&domain.Attachment{})
- if err != nil {
- return err
- }
- }
-
- // Delete message
- if err := tx.DeleteStruct(msg); err != nil {
- return err
- }
-
- if err := tx.Commit(); err != nil {
- return err
- }
-
- for _, att := range atts {
- if err := os.Remove(db.getAttachmentPath(&att)); err != nil {
- log.Println("database.DB.DeleteMessage: could not delete attachment data:", err)
- }
- }
-
- return nil
-}
-
-func (db *DB) CreateAttachment(att *domain.Attachment) error {
- err := db.db.Save(att)
- if err != nil {
- return err
- }
-
- return os.WriteFile(db.getAttachmentPath(att), att.Data, 0644)
-}
-
-// getAttachmentPath returns the path to the attachment file on the file system.
-func (db *DB) getAttachmentPath(att *domain.Attachment) string {
- return path.Join(db.attDir, db.GetAttachmentFile(att))
-}
-
-func (db *DB) GetAttachmentFile(att *domain.Attachment) string {
- return fmt.Sprintf("%s.%s", att.UUID, att.Type)
-}
-
-func (db *DB) GetAttachmentFS() fs.FS {
- return os.DirFS(db.attDir)
-}
-
-func (db *DB) GetAttachment(uuid string) (*domain.Attachment, error) {
- var att domain.Attachment
- err := db.db.One("UUID", uuid, att)
- if err != nil {
- return nil, err
- }
-
- return &att, nil
-}
-
-func (db *DB) GetAttachmentData(att *domain.Attachment) ([]byte, error) {
- data, err := os.ReadFile(db.getAttachmentPath(att))
- if err != nil {
- return nil, err
- }
-
- return data, nil
-}
-
-func (db *DB) GetAttachments(msg *domain.Message) ([]domain.Attachment, error) {
- var atts []domain.Attachment
- err := db.db.Select(q.Eq("MessageUUID", msg.UUID)).Find(&atts)
- if err != nil {
- if err == storm.ErrNotFound {
- return []domain.Attachment{}, nil
- }
- return nil, err
- }
-
- return atts, nil
-}
diff --git a/right/database/message.go b/right/database/message.go
new file mode 100644
index 00000000..291c3430
--- /dev/null
+++ b/right/database/message.go
@@ -0,0 +1,101 @@
+package database
+
+import (
+ "log"
+ "os"
+
+ "github.com/ItsNotGoodName/smtpbridge/domain"
+ "github.com/asdine/storm"
+ "github.com/asdine/storm/q"
+)
+
+func (db *DB) CreateMessage(msg *domain.Message) error {
+ return db.db.Save(msg)
+}
+
+func (db *DB) GetMessage(uuid string) (*domain.Message, error) {
+ var msg domain.Message
+ err := db.db.One("UUID", uuid, msg)
+ if err != nil {
+ return nil, err
+ }
+
+ return &msg, nil
+}
+
+func (db *DB) UpdateMessage(msg *domain.Message, updateFN func(msg *domain.Message) (*domain.Message, error)) error {
+ tx, err := db.db.Begin(true)
+ if err != nil {
+ return err
+ }
+ defer tx.Rollback()
+
+ var existingMSG domain.Message
+ if err := tx.One("UUID", msg.UUID, &existingMSG); err != nil {
+ return err
+ }
+
+ updatedMSG, err := updateFN(&existingMSG)
+ if err != nil {
+ return err
+ }
+
+ err = tx.Save(updatedMSG)
+ if err != nil {
+ return err
+ }
+
+ return tx.Commit()
+}
+
+func (db *DB) GetMessages(limit, offset int) ([]domain.Message, error) {
+ var msgs []domain.Message
+ err := db.db.Select().OrderBy("CreatedAt").Limit(limit).Skip(offset).Reverse().Find(&msgs)
+ if err != nil && err != storm.ErrNotFound {
+ return nil, err
+ }
+
+ return msgs, nil
+}
+
+func (db *DB) DeleteMessage(msg *domain.Message) error {
+ tx, err := db.db.Begin(true)
+ if err != nil {
+ return err
+ }
+ defer tx.Rollback()
+
+ query := tx.Select(q.Eq("MessageUUID", msg.UUID))
+
+ // List attachments
+ var atts []domain.Attachment
+ err = query.Find(&atts)
+ if err != storm.ErrNotFound {
+ if err != nil {
+ return err
+ }
+
+ // Delete attachments
+ err = query.Delete(&domain.Attachment{})
+ if err != nil {
+ return err
+ }
+ }
+
+ // Delete message
+ if err := tx.DeleteStruct(msg); err != nil {
+ return err
+ }
+
+ if err := tx.Commit(); err != nil {
+ return err
+ }
+
+ for _, att := range atts {
+ if err := os.Remove(db.getAttachmentPath(&att)); err != nil {
+ log.Println("database.DB.DeleteMessage: could not delete attachment data:", err)
+ }
+ }
+
+ return nil
+}