fake-smtp/internal/route/email.go

201 lines
4.4 KiB
Go

package route
import (
"context"
"net/http"
"strconv"
"github.com/microcosm-cc/bluemonday"
"forge.cadoles.com/wpetit/fake-smtp/internal/command"
"forge.cadoles.com/wpetit/fake-smtp/internal/model"
"forge.cadoles.com/wpetit/fake-smtp/internal/query"
"forge.cadoles.com/wpetit/fake-smtp/internal/storm"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/cqrs"
"gitlab.com/wpetit/goweb/middleware/container"
"gitlab.com/wpetit/goweb/service/template"
)
func serveEmailPage(w http.ResponseWriter, r *http.Request) {
emailID, err := getEmailID(r)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
ctx := r.Context()
email, err := openEmail(ctx, emailID)
if err != nil {
if errors.Is(err, storm.ErrNotFound) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
panic(errors.Wrap(err, "could not open email"))
}
ctn := container.Must(ctx)
tmpl := template.Must(ctn)
data := extendTemplateData(w, r, template.Data{
"Email": email,
})
if err := tmpl.RenderPage(w, "email.html.tmpl", data); err != nil {
panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path))
}
}
func serveEmailHTMLContent(w http.ResponseWriter, r *http.Request) {
emailID, err := getEmailID(r)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
ctx := r.Context()
email, err := openEmail(ctx, emailID)
if err != nil {
if errors.Is(err, storm.ErrNotFound) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
panic(errors.Wrap(err, "could not open email"))
}
html := email.HTML
if html == "" {
http.Error(w, http.StatusText(http.StatusNoContent), http.StatusNoContent)
return
}
policy := bluemonday.UGCPolicy()
sanitizedHTML := policy.Sanitize(email.HTML)
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(sanitizedHTML))
}
func serveEmailAttachment(w http.ResponseWriter, r *http.Request) {
emailID, err := getEmailID(r)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
ctx := r.Context()
email, err := openEmail(ctx, emailID)
if err != nil {
if errors.Is(err, storm.ErrNotFound) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
panic(errors.Wrap(err, "could not open email"))
}
attachmentIndex, err := getAttachmentIndex(r)
if err != nil {
if errors.Is(err, storm.ErrNotFound) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
panic(errors.Wrap(err, "could not open attachment"))
}
if attachmentIndex < 0 || attachmentIndex >= len(email.Attachments) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
attachment := email.Attachments[attachmentIndex]
w.Header().Set("Content-Type", attachment.ContentType)
if _, err := w.Write(attachment.Data); err != nil {
panic(errors.Wrap(err, "could not send attachment"))
}
}
func handleEmailDelete(w http.ResponseWriter, r *http.Request) {
emailID, err := getEmailID(r)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
ctx := r.Context()
ctn := container.Must(ctx)
bus := cqrs.Must(ctn)
deleteEmail := &command.DeleteEmailRequest{
EmailID: emailID,
}
if _, err := bus.Exec(ctx, deleteEmail); err != nil {
panic(errors.Wrap(err, "could not delete email"))
}
http.Error(w, http.StatusText(http.StatusNoContent), http.StatusNoContent)
}
func getEmailID(r *http.Request) (int, error) {
rawEmailID := chi.URLParam(r, "id")
emailID, err := strconv.ParseInt(rawEmailID, 10, 32)
if err != nil {
return 0, err
}
return int(emailID), nil
}
func openEmail(ctx context.Context, emailID int) (*model.Email, error) {
ctn := container.Must(ctx)
bus := cqrs.Must(ctn)
req := &query.OpenEmailRequest{
EmailID: int(emailID),
}
result, err := bus.Query(ctx, req)
if err != nil {
return nil, err
}
openEmailData, ok := result.Data().(*query.OpenEmailData)
if !ok {
return nil, errors.New("unexpected result data")
}
return openEmailData.Email, nil
}
func getAttachmentIndex(r *http.Request) (int, error) {
rawAttachmendIndex := chi.URLParam(r, "attachmendIndex")
attachmendIndex, err := strconv.ParseInt(rawAttachmendIndex, 10, 32)
if err != nil {
return 0, err
}
return int(attachmendIndex), nil
}