mirror of
https://github.com/axllent/mailpit.git
synced 2025-02-05 13:14:57 +02:00
Merge branch 'feature/ui-tests' into develop
This commit is contained in:
commit
3e90391991
@ -81,6 +81,13 @@ type textResponse struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
// HTML response
|
||||
// swagger:response HTMLResponse
|
||||
type htmlResponse struct {
|
||||
// in: body
|
||||
Body string
|
||||
}
|
||||
|
||||
// Error response
|
||||
// swagger:response ErrorResponse
|
||||
type errorResponse struct {
|
||||
|
163
server/handlers/message-rendered.go
Normal file
163
server/handlers/message-rendered.go
Normal file
@ -0,0 +1,163 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/axllent/mailpit/config"
|
||||
"github.com/axllent/mailpit/internal/storage"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// GetMessageHTML (method: GET) returns a rendered version of a message's HTML part
|
||||
func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:route GET /view/{ID}.html testing GetMessageHTML
|
||||
//
|
||||
// # Render message HTML part
|
||||
//
|
||||
// Renders just the message's HTML part which can be used for UI integration testing.
|
||||
// Attached inline images are modified to link to the API provided they exist.
|
||||
// Note that is the message does not contain a HTML part then an 404 error is returned.
|
||||
//
|
||||
// The ID can be set to `latest` to return the latest message.
|
||||
//
|
||||
// Produces:
|
||||
// - text/html
|
||||
//
|
||||
// Schemes: http, https
|
||||
//
|
||||
// Parameters:
|
||||
// + name: ID
|
||||
// in: path
|
||||
// description: Database ID or latest
|
||||
// required: true
|
||||
// type: string
|
||||
//
|
||||
// Responses:
|
||||
// 200: HTMLResponse
|
||||
// default: ErrorResponse
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
id := vars["id"]
|
||||
|
||||
if id == "latest" {
|
||||
messages, err := storage.List(0, 1)
|
||||
if err != nil {
|
||||
httpError(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprint(w, "Message not found")
|
||||
return
|
||||
}
|
||||
|
||||
id = messages[0].ID
|
||||
}
|
||||
|
||||
msg, err := storage.GetMessage(id)
|
||||
if err != nil {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprint(w, "Message not found")
|
||||
return
|
||||
}
|
||||
if msg.HTML == "" {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprint(w, "This message does not contain a HTML part")
|
||||
return
|
||||
}
|
||||
|
||||
html := linkInlinedImages(msg)
|
||||
w.Header().Add("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = w.Write([]byte(html))
|
||||
}
|
||||
|
||||
// GetMessageText (method: GET) returns a message's text part
|
||||
func GetMessageText(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:route GET /view/{ID}.txt testing GetMessageText
|
||||
//
|
||||
// # Render message text part
|
||||
//
|
||||
// Renders just the message's text part which can be used for UI integration testing.
|
||||
//
|
||||
// The ID can be set to `latest` to return the latest message.
|
||||
//
|
||||
// Produces:
|
||||
// - text/plain
|
||||
//
|
||||
// Schemes: http, https
|
||||
//
|
||||
// Parameters:
|
||||
// + name: ID
|
||||
// in: path
|
||||
// description: Database ID or latest
|
||||
// required: true
|
||||
// type: string
|
||||
//
|
||||
// Responses:
|
||||
// 200: TextResponse
|
||||
// default: ErrorResponse
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
id := vars["id"]
|
||||
|
||||
if id == "latest" {
|
||||
messages, err := storage.List(0, 1)
|
||||
if err != nil {
|
||||
httpError(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(messages) == 0 {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprint(w, "Message not found")
|
||||
return
|
||||
}
|
||||
|
||||
id = messages[0].ID
|
||||
}
|
||||
|
||||
msg, err := storage.GetMessage(id)
|
||||
if err != nil {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprint(w, "Message not found")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Content-Type", "text/plain; charset=utf-8")
|
||||
_, _ = w.Write([]byte(msg.Text))
|
||||
}
|
||||
|
||||
// This will remap all attachment images with relative paths
|
||||
func linkInlinedImages(msg *storage.Message) string {
|
||||
html := msg.HTML
|
||||
|
||||
for _, a := range msg.Inline {
|
||||
if a.ContentID != "" {
|
||||
re := regexp.MustCompile(`(?i)(=["\']?)(cid:` + regexp.QuoteMeta(a.ContentID) + `)(["|\'|\\s|\\/|>|;])`)
|
||||
u := config.Webroot + "api/v1/message/" + msg.ID + "/part/" + a.PartID
|
||||
matches := re.FindAllStringSubmatch(html, -1)
|
||||
for _, m := range matches {
|
||||
html = strings.ReplaceAll(html, m[0], m[1]+u+m[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, a := range msg.Attachments {
|
||||
if a.ContentID != "" {
|
||||
re := regexp.MustCompile(`(?i)(=["\']?)(cid:` + regexp.QuoteMeta(a.ContentID) + `)(["|\'|\\s|\\/|>|;])`)
|
||||
u := config.Webroot + "api/v1/message/" + msg.ID + "/part/" + a.PartID
|
||||
matches := re.FindAllStringSubmatch(html, -1)
|
||||
for _, m := range matches {
|
||||
html = strings.ReplaceAll(html, m[0], m[1]+u+m[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return html
|
||||
}
|
@ -67,8 +67,14 @@ func Listen() {
|
||||
r.HandleFunc(redirect, middleWareFunc(addSlashToWebroot)).Methods("GET")
|
||||
}
|
||||
|
||||
// handle everything else with the virtual index.html
|
||||
r.PathPrefix(config.Webroot).Handler(middleWareFunc(index)).Methods("GET")
|
||||
// frontend testing
|
||||
r.HandleFunc(config.Webroot+"view/{id}.html", handlers.GetMessageHTML).Methods("GET")
|
||||
r.HandleFunc(config.Webroot+"view/{id}.txt", handlers.GetMessageText).Methods("GET")
|
||||
|
||||
// web UI via virtual index.html
|
||||
r.PathPrefix(config.Webroot + "view/").Handler(middleWareFunc(index)).Methods("GET")
|
||||
r.Path(config.Webroot + "search").Handler(middleWareFunc(index)).Methods("GET")
|
||||
r.Path(config.Webroot).Handler(middleWareFunc(index)).Methods("GET")
|
||||
|
||||
// put it all together
|
||||
http.Handle("/", r)
|
||||
@ -293,10 +299,6 @@ func index(w http.ResponseWriter, _ *http.Request) {
|
||||
|
||||
buff.Bytes()
|
||||
|
||||
// f, err := embeddedFS.ReadFile("public/index.html")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
_, _ = w.Write(buff.Bytes())
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export default {
|
||||
return false
|
||||
}
|
||||
|
||||
let re = new RegExp(`\\btag:"?${tag}"?\\b`, 'i')
|
||||
let re = new RegExp(`\\b[^\-!]tag:"?${tag}"?\\b`, 'i')
|
||||
return query.match(re)
|
||||
}
|
||||
}
|
||||
|
@ -654,6 +654,74 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/view/{ID}.html": {
|
||||
"get": {
|
||||
"description": "Renders just the message's HTML part which can be used for UI integration testing.\nAttached inline images are modified to link to the API provided they exist.\nNote that is the message does not contain a HTML part then an 404 error is returned.\n\nThe ID can be set to `latest` to return the latest message.",
|
||||
"produces": [
|
||||
"text/html"
|
||||
],
|
||||
"schemes": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"testing"
|
||||
],
|
||||
"summary": "Render message HTML part",
|
||||
"operationId": "GetMessageHTML",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Database ID or latest",
|
||||
"name": "ID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/HTMLResponse"
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/responses/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/view/{ID}.txt": {
|
||||
"get": {
|
||||
"description": "Renders just the message's text part which can be used for UI integration testing.\n\nThe ID can be set to `latest` to return the latest message.",
|
||||
"produces": [
|
||||
"text/plain"
|
||||
],
|
||||
"schemes": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"testing"
|
||||
],
|
||||
"summary": "Render message text part",
|
||||
"operationId": "GetMessageText",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Database ID or latest",
|
||||
"name": "ID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/TextResponse"
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/responses/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@ -1300,6 +1368,9 @@
|
||||
"ErrorResponse": {
|
||||
"description": "Error response"
|
||||
},
|
||||
"HTMLResponse": {
|
||||
"description": "HTML response"
|
||||
},
|
||||
"InfoResponse": {
|
||||
"description": "Application information",
|
||||
"schema": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user