mirror of
				https://github.com/aykhans/slash-e.git
				synced 2025-11-04 10:49:58 +00:00 
			
		
		
		
	chore: fix tests
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@@ -69,6 +69,7 @@ require (
 | 
			
		||||
	github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0
 | 
			
		||||
	github.com/improbable-eng/grpc-web v0.15.0
 | 
			
		||||
	github.com/joho/godotenv v1.5.1
 | 
			
		||||
	github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
 | 
			
		||||
	github.com/lib/pq v1.10.9
 | 
			
		||||
	github.com/mssola/useragent v1.0.0
 | 
			
		||||
	github.com/nyaruka/phonenumbers v1.4.0
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@@ -183,6 +183,8 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht
 | 
			
		||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
			
		||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
			
		||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 | 
			
		||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
 | 
			
		||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
 | 
			
		||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 | 
			
		||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
			
		||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net/mail"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
@@ -146,11 +147,17 @@ func TruncateString(str string, limit int) (string, bool) {
 | 
			
		||||
	return str, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TruncateStringWithDescription tries to truncate the string and append "... (view details in Bytebase)" if truncated.
 | 
			
		||||
// TruncateStringWithDescription tries to truncate the string and append "..." if truncated.
 | 
			
		||||
func TruncateStringWithDescription(str string) string {
 | 
			
		||||
	const limit = 450
 | 
			
		||||
	if truncatedStr, truncated := TruncateString(str, limit); truncated {
 | 
			
		||||
		return fmt.Sprintf("%s... (view details in Bytebase)", truncatedStr)
 | 
			
		||||
		return fmt.Sprintf("%s...", truncatedStr)
 | 
			
		||||
	}
 | 
			
		||||
	return str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateURI validates the URI.
 | 
			
		||||
func ValidateURI(uri string) bool {
 | 
			
		||||
	u, err := url.Parse(uri)
 | 
			
		||||
	return err == nil && u.Scheme != "" && u.Host != ""
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								plugin/mail/login_auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								plugin/mail/login_auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
package mail
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/smtp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type loginAuth struct {
 | 
			
		||||
	username string
 | 
			
		||||
	password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoginAuth returns an Auth that implements the LOGIN authentication.
 | 
			
		||||
func LoginAuth(username, password string) smtp.Auth {
 | 
			
		||||
	return &loginAuth{username, password}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*loginAuth) Start(*smtp.ServerInfo) (string, []byte, error) {
 | 
			
		||||
	return "LOGIN", []byte{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (la *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
 | 
			
		||||
	if more {
 | 
			
		||||
		switch string(fromServer) {
 | 
			
		||||
		case "Username:":
 | 
			
		||||
			return []byte(la.username), nil
 | 
			
		||||
		case "Password:":
 | 
			
		||||
			return []byte(la.password), nil
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, errors.New("Unknown fromServer")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										230
									
								
								plugin/mail/mail.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								plugin/mail/mail.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
			
		||||
// Package mail is a mail delivery plugin based on SMTP.
 | 
			
		||||
package mail
 | 
			
		||||
 | 
			
		||||
// Usage:
 | 
			
		||||
//  email := NewEmailMsg().SetFrom("yourselfhosted <from@yourselfhosted.com>").AddTo("Customer <to@yourselfhosted.com>").SetSubject("Test Email Subject").SetBody(`
 | 
			
		||||
// <!DOCTYPE html>
 | 
			
		||||
// <html>
 | 
			
		||||
// <head>
 | 
			
		||||
// 	<title>HTML Test</title>
 | 
			
		||||
// </head>
 | 
			
		||||
// <body>
 | 
			
		||||
// 	<h1>This is a mail delivery test.</h1>
 | 
			
		||||
// </body>
 | 
			
		||||
// </html>
 | 
			
		||||
// 	`)
 | 
			
		||||
// 	fmt.Printf("email: %+v\n", email)
 | 
			
		||||
// 	client := NewSMTPClient("smtp.gmail.com", 587)
 | 
			
		||||
// 	client.SetAuthType(SMTPAuthTypePlain)
 | 
			
		||||
// 	client.SetAuthCredentials("from@yourselfhosted.com", "nqxxxxxxxxxxxxxx")
 | 
			
		||||
// 	client.SetEncryptionType(SMTPEncryptionTypeSTARTTLS)
 | 
			
		||||
// 	if err := client.SendMail(email); err != nil {
 | 
			
		||||
// 		t.Fatalf("SendMail failed: %v", err)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/mail"
 | 
			
		||||
	"net/smtp"
 | 
			
		||||
 | 
			
		||||
	"github.com/jordan-wright/email"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Email is the email to be sent.
 | 
			
		||||
type Email struct {
 | 
			
		||||
	err     error
 | 
			
		||||
	from    string
 | 
			
		||||
	subject string
 | 
			
		||||
 | 
			
		||||
	e *email.Email
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEmailMsg returns a new email message.
 | 
			
		||||
func NewEmailMsg() *Email {
 | 
			
		||||
	e := &Email{
 | 
			
		||||
		e: email.NewEmail(),
 | 
			
		||||
	}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetFrom sets the from address of the SMTP client.
 | 
			
		||||
// Only accept the valid RFC 5322 address, e.g. "yourselfhosted <support@yourselfhosted.com>".
 | 
			
		||||
func (e *Email) SetFrom(from string) *Email {
 | 
			
		||||
	if e.err != nil {
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	if e.from != "" {
 | 
			
		||||
		e.err = errors.New("From address already set")
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parsedAddr, err := mail.ParseAddress(from)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		e.err = errors.Wrapf(err, "Invalid from address: %s", from)
 | 
			
		||||
	}
 | 
			
		||||
	e.from = parsedAddr.Address
 | 
			
		||||
	e.e.From = parsedAddr.String()
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTo adds the to address of the SMTP client.
 | 
			
		||||
// Only accept the valid RFC 5322 address, e.g. "yourselfhosted <support@yourselfhosted.com>".
 | 
			
		||||
func (e *Email) AddTo(to ...string) *Email {
 | 
			
		||||
	if e.err != nil {
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	var buf []*mail.Address
 | 
			
		||||
	for _, toAddress := range to {
 | 
			
		||||
		parsedAddr, err := mail.ParseAddress(toAddress)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			e.err = errors.Wrapf(err, "Invalid to address: %s", toAddress)
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
		buf = append(buf, parsedAddr)
 | 
			
		||||
	}
 | 
			
		||||
	for _, addr := range buf {
 | 
			
		||||
		e.e.To = append(e.e.To, addr.String())
 | 
			
		||||
	}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetSubject sets the subject of the SMTP client.
 | 
			
		||||
func (e *Email) SetSubject(subject string) *Email {
 | 
			
		||||
	if e.err != nil {
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	if e.subject != "" {
 | 
			
		||||
		e.err = errors.New("Subject already set")
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	e.subject = subject
 | 
			
		||||
	e.e.Subject = subject
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetBody sets the body of the SMTP client. It must be html formatted.
 | 
			
		||||
func (e *Email) SetBody(body string) *Email {
 | 
			
		||||
	e.e.HTML = []byte(body)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The ContentType is the type of the content.
 | 
			
		||||
// https://cloud.google.com/appengine/docs/legacy/standard/php/mail/mail-with-headers-attachments.
 | 
			
		||||
type ContentType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ContentTypeImagePNG is the content type of the file with png extension.
 | 
			
		||||
	ContentTypeImagePNG ContentType = "image/png"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Attach attaches the file to the email, and returns the filename of the attachment.
 | 
			
		||||
// Caller can use filename as content id to reference the attachment in the email body.
 | 
			
		||||
func (e *Email) Attach(reader io.Reader, filename string, contentType ContentType) (string, error) {
 | 
			
		||||
	attachment, err := e.e.Attach(reader, filename, string(contentType))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return attachment.Filename, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SMTPAuthType is the type of SMTP authentication.
 | 
			
		||||
type SMTPAuthType uint
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// SMTPAuthTypeNone is the NONE auth type of SMTP.
 | 
			
		||||
	SMTPAuthTypeNone = iota
 | 
			
		||||
	// SMTPAuthTypePlain is the PLAIN auth type of SMTP.
 | 
			
		||||
	SMTPAuthTypePlain
 | 
			
		||||
	// SMTPAuthTypeLogin is the LOGIN auth type of SMTP.
 | 
			
		||||
	SMTPAuthTypeLogin
 | 
			
		||||
	// SMTPAuthTypeCRAMMD5 is the CRAM-MD5 auth type of SMTP.
 | 
			
		||||
	SMTPAuthTypeCRAMMD5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SMTPEncryptionType is the type of SMTP encryption.
 | 
			
		||||
type SMTPEncryptionType uint
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// SMTPEncryptionTypeNone is the NONE encrypt type of SMTP.
 | 
			
		||||
	SMTPEncryptionTypeNone = iota
 | 
			
		||||
	// SMTPEncryptionTypeSSLTLS is the SSL/TLS encrypt type of SMTP.
 | 
			
		||||
	SMTPEncryptionTypeSSLTLS
 | 
			
		||||
	// SMTPEncryptionTypeSTARTTLS is the STARTTLS encrypt type of SMTP.
 | 
			
		||||
	SMTPEncryptionTypeSTARTTLS
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SMTPClient is the client of SMTP.
 | 
			
		||||
type SMTPClient struct {
 | 
			
		||||
	host           string
 | 
			
		||||
	port           int
 | 
			
		||||
	authType       SMTPAuthType
 | 
			
		||||
	username       string
 | 
			
		||||
	password       string
 | 
			
		||||
	encryptionType SMTPEncryptionType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSMTPClient returns a new SMTP client.
 | 
			
		||||
func NewSMTPClient(host string, port int) *SMTPClient {
 | 
			
		||||
	return &SMTPClient{
 | 
			
		||||
		host:           host,
 | 
			
		||||
		port:           port,
 | 
			
		||||
		authType:       SMTPAuthTypeNone,
 | 
			
		||||
		username:       "",
 | 
			
		||||
		password:       "",
 | 
			
		||||
		encryptionType: SMTPEncryptionTypeNone,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendMail sends the email.
 | 
			
		||||
func (c *SMTPClient) SendMail(e *Email) error {
 | 
			
		||||
	if e.err != nil {
 | 
			
		||||
		return e.err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch c.encryptionType {
 | 
			
		||||
	case SMTPEncryptionTypeNone:
 | 
			
		||||
		return e.e.Send(fmt.Sprintf("%s:%d", c.host, c.port), c.getAuth())
 | 
			
		||||
	case SMTPEncryptionTypeSSLTLS:
 | 
			
		||||
		return e.e.SendWithTLS(fmt.Sprintf("%s:%d", c.host, c.port), c.getAuth(), &tls.Config{ServerName: c.host})
 | 
			
		||||
	case SMTPEncryptionTypeSTARTTLS:
 | 
			
		||||
		return e.e.SendWithStartTLS(fmt.Sprintf("%s:%d", c.host, c.port), c.getAuth(), &tls.Config{InsecureSkipVerify: true})
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.Errorf("Unknown SMTP encryption type: %d", c.encryptionType)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAuthType sets the auth type of the SMTP client.
 | 
			
		||||
func (c *SMTPClient) SetAuthType(authType SMTPAuthType) *SMTPClient {
 | 
			
		||||
	c.authType = authType
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAuthCredentials sets the auth credentials of the SMTP client.
 | 
			
		||||
func (c *SMTPClient) SetAuthCredentials(username, password string) *SMTPClient {
 | 
			
		||||
	c.username = username
 | 
			
		||||
	c.password = password
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *SMTPClient) getAuth() smtp.Auth {
 | 
			
		||||
	switch c.authType {
 | 
			
		||||
	case SMTPAuthTypeNone:
 | 
			
		||||
		return nil
 | 
			
		||||
	case SMTPAuthTypePlain:
 | 
			
		||||
		return smtp.PlainAuth("", c.username, c.password, c.host)
 | 
			
		||||
	case SMTPAuthTypeLogin:
 | 
			
		||||
		return LoginAuth(c.username, c.password)
 | 
			
		||||
	case SMTPAuthTypeCRAMMD5:
 | 
			
		||||
		return smtp.CRAMMD5Auth(c.username, c.password)
 | 
			
		||||
	default:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetEncryptionType sets the encryption type of the SMTP client.
 | 
			
		||||
func (c *SMTPClient) SetEncryptionType(encryptionType SMTPEncryptionType) {
 | 
			
		||||
	c.encryptionType = encryptionType
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user