diff --git a/config/config.go b/config/config.go index 26b32f1..744b3ff 100644 --- a/config/config.go +++ b/config/config.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/axllent/mailpit/utils/logger" + "github.com/axllent/mailpit/utils/tools" "github.com/mattn/go-shellwords" "github.com/tg123/go-htpasswd" "gopkg.in/yaml.v3" @@ -41,7 +42,7 @@ var ( // UIAuthFile for basic authentication UIAuthFile string - // UIAuth used for euthentication + // UIAuth used for authentication UIAuth *htpasswd.File // Webroot to define the base path for the UI and API @@ -71,8 +72,8 @@ var ( // SMTPCLITags is used to map the CLI args SMTPCLITags string - // TagRegexp is the allowed tag characters - TagRegexp = regexp.MustCompile(`^([a-zA-Z0-9\-\ \_]){3,}$`) + // ValidTagRegexp represents a valid tag + ValidTagRegexp = regexp.MustCompile(`^([a-zA-Z0-9\-\ \_]){3,}$`) // SMTPTags are expressions to apply tags to new mail SMTPTags []AutoTag @@ -86,7 +87,7 @@ var ( // ReleaseEnabled is whether message releases are enabled, requires a valid SMTPRelayConfigFile ReleaseEnabled = false - // SMTPRelayAllIncoming is whether to relay all incoming messages via preconfgured SMTP server. + // SMTPRelayAllIncoming is whether to relay all incoming messages via pre-configured SMTP server. // Use with extreme caution! SMTPRelayAllIncoming = false @@ -219,8 +220,8 @@ func VerifyConfig() error { for _, a := range args { t := strings.Split(a, "=") if len(t) > 1 { - tag := strings.TrimSpace(t[0]) - if !TagRegexp.MatchString(tag) || len(tag) == 0 { + tag := tools.CleanTag(t[0]) + if !ValidTagRegexp.MatchString(tag) || len(tag) == 0 { return fmt.Errorf("Invalid tag (%s) - can only contain spaces, letters, numbers, - & _", tag) } match := strings.TrimSpace(strings.ToLower(strings.Join(t[1:], "="))) diff --git a/server/ui-src/App.vue b/server/ui-src/App.vue index 4bfd9a5..1432b01 100644 --- a/server/ui-src/App.vue +++ b/server/ui-src/App.vue @@ -74,6 +74,13 @@ export default { }, canNext: function () { return this.total > (this.start + this.count); + }, + unreadInSearch: function () { + if (!this.searching) { + return false; + } + + return this.items.filter(i => !i.Read).length; } }, @@ -304,6 +311,24 @@ export default { }); }, + // delete messages displayed in current search + deleteSearch: function () { + let ids = this.items.map(item => item.ID); + + if (!ids.length) { + return false; + } + + let self = this; + let uri = 'api/v1/messages'; + self.delete(uri, { 'ids': ids }, function (response) { + window.location.hash = ""; + self.scrollInPlace = true; + self.loadMessages(); + }); + }, + + // delete all messages from mailbox deleteAll: function () { let self = this; let uri = 'api/v1/messages'; @@ -313,6 +338,7 @@ export default { }); }, + // mark current message as read markUnread: function () { let self = this; if (!self.message) { @@ -326,6 +352,7 @@ export default { }); }, + // mark all messages in mailbox as read markAllRead: function () { let self = this; let uri = 'api/v1/messages' @@ -336,6 +363,24 @@ export default { }); }, + // mark messages in current search as read + markSearchRead: function () { + let ids = this.items.map(item => item.ID); + + if (!ids.length) { + return false; + } + + let self = this; + let uri = 'api/v1/messages'; + self.put(uri, { 'read': true, 'ids': ids }, function (response) { + window.location.hash = ""; + self.scrollInPlace = true; + self.loadMessages(); + }); + }, + + // mark selected messages as read markSelectedRead: function () { let self = this; if (!self.selected.length) { @@ -349,6 +394,7 @@ export default { }); }, + // mark selected messages as unread markSelectedUnread: function () { let self = this; if (!self.selected.length) { @@ -362,7 +408,7 @@ export default { }); }, - // test of any selected emails are unread + // test if any selected emails are unread selectedHasUnread: function () { if (!this.selected.length) { return false; @@ -709,7 +755,8 @@ export default { Mailpit
- +
@@ -720,14 +767,29 @@ export default {
- + + + + +