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/v5" "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 }