From b5ed7342a02825f50dc8edaa953263008b6b7929 Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Tue, 29 Oct 2019 00:52:11 -0400 Subject: [PATCH] email: example email working --- .gitignore | 1 + Makefile | 6 ++-- email/email.go | 75 ++++++++++++++++++++++++++++++++++++++++++++ go.mod | 13 ++++---- go.sum | 22 +++++++++++++ serve.go | 84 ++++++++++++++++++++++++++++---------------------- user/user.go | 50 ++++++++++++++++++++++++++++++ 7 files changed, 207 insertions(+), 44 deletions(-) create mode 100644 email/email.go create mode 100644 user/user.go diff --git a/.gitignore b/.gitignore index e3fba51..cd668bf 100644 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,4 @@ happy frontend/dist *.db *-packr.go +env.make diff --git a/Makefile b/Makefile index 92d3aaa..17dc299 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +-include env.make + frontend-deps: frontend/node_modules cd frontend && yarn @@ -10,7 +12,7 @@ frontend: frontend-deps frontend-watch: cd frontend && yarn build --watch -run: *.go +run: *.go .EXPORT_ALL_VARIABLES go build && ./happy -develop -.PHONY: run frontend frontend-watch +.PHONY: run frontend frontend-watch .EXPORT_ALL_VARIABLES diff --git a/email/email.go b/email/email.go new file mode 100644 index 0000000..78ed93c --- /dev/null +++ b/email/email.go @@ -0,0 +1,75 @@ +package email + +import ( + "bytes" + "text/template" + "time" + + "code.chrissexton.org/cws/happy/user" + + mail "github.com/xhit/go-simple-mail" +) + +var NoReply = `noreply@chrissexton.org` +var NewUserSubject = `Welcome to Happy` +var NewUserBody = `Welcome, {{.String}}, + +You may activate your new account with this link: +{{.BaseURL}}/user/{{.String}}/{{.Verification}} + +Be sure to keep this URL and use it to log in to any devices. If you should lose it, just ask for a new one via the website. +You should always see {{.String}} at the bottom of the screen if you are logged in to this account.` + +var newUserTpl = template.Must(template.New("NewUser").Parse(NewUserBody)) + +type EMailClient struct { + *mail.SMTPServer +} + +func New(addr string, port int, user, pass string) *EMailClient { + m := EMailClient{ + mail.NewSMTPClient(), + } + m.Host = addr + m.Port = port + m.Username = user + m.Password = pass + m.Encryption = mail.EncryptionTLS + + m.KeepAlive = false + m.ConnectTimeout = 10 * time.Second + m.SendTimeout = 10 * time.Second + + return &m +} + +func (e *EMailClient) Send(from, to, subject, body string, isHTML bool) error { + client, err := e.Connect() + if err != nil { + return err + } + msg := mail.NewMSG() + + if isHTML { + msg.SetBody(mail.TextHTML, body) + } else { + msg.SetBody(mail.TextPlain, body) + } + + msg.SetFrom(from). + AddTo(to). + SetSubject(subject) + + err = msg.Send(client) + return err +} + +func (e *EMailClient) SendNewUserMail(to string, u user.User, url string) error { + w := bytes.NewBufferString("") + tplArgs := struct { + user.User + BaseURL string + }{u, url} + newUserTpl.Execute(w, tplArgs) + return e.Send(NoReply, to, NewUserSubject, w.String(), false) +} diff --git a/go.mod b/go.mod index 5d7197d..d7b4d30 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/chrissexton/happy +module code.chrissexton.org/cws/happy go 1.12 @@ -6,16 +6,17 @@ require ( github.com/gobuffalo/packr/v2 v2.7.1 github.com/gorilla/mux v1.7.3 github.com/jmoiron/sqlx v1.2.0 - github.com/mattn/go-sqlite3 v1.9.0 + github.com/mattn/go-sqlite3 v1.11.0 github.com/rogpeppe/go-internal v1.5.0 // indirect - github.com/rs/zerolog v1.15.0 + github.com/rs/zerolog v1.16.0 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd // indirect github.com/speps/go-hashids v2.0.0+incompatible github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/graceful v1.2.15 - golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 // indirect - golang.org/x/sys v0.0.0-20191028145128-b67d8b46d239 // indirect - golang.org/x/tools v0.0.0-20191028143239-8715e36070db // indirect + github.com/xhit/go-simple-mail v2.2.2+incompatible + golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect + golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 // indirect + golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c // indirect google.golang.org/appengine v1.6.5 // indirect ) diff --git a/go.sum b/go.sum index 4024e6d..427cac0 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +code.chrissexton.org/cws/happy v0.0.0-20191028162954-154f2a51960e h1:z5VkC/O60AYvzRtMLCGI2f4jKDkZkAFDVjCfUJfrfug= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -6,6 +7,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= @@ -33,18 +35,23 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -56,6 +63,8 @@ github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/rs/zerolog v1.16.0 h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q= +github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= @@ -81,8 +90,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xhit/go-simple-mail v2.2.2+incompatible h1:Hm2VGfLqiQJ/NnC8SYsrPOPyVYIlvP2kmnotP4RIV74= +github.com/xhit/go-simple-mail v2.2.2+incompatible/go.mod h1:I8Ctg6vIJZ+Sv7k/22M6oeu/tbFumDY0uxBuuLbtU7Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -91,11 +103,14 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhi golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3ob3lmhYIefc+GU+DLg1Ow= golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIoF2s4qxv0xSSS0BVZUE/ss= +golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= @@ -108,20 +123,27 @@ golang.org/x/sys v0.0.0-20190515120540-06a5c4944438 h1:khxRGsvPk4n2y8I/mLLjp7e5d golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191028145128-b67d8b46d239 h1:UTx+LbSWbZFJ8IFqpAx3ns0lPXY+EBFKtDZRiyILdn0= golang.org/x/sys v0.0.0-20191028145128-b67d8b46d239/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49njPFDLSd3z+X1HgWDMpE= +golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3 h1:2AmBLzhAfXj+2HCW09VCkJtHIYgHTIPcTeYqgP7Bwt0= golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191028143239-8715e36070db h1:xzcb0oYS6YlLAFxFJtuJ5GS6TVcVi3zQsh5Pf6LtASA= golang.org/x/tools v0.0.0-20191028143239-8715e36070db/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/serve.go b/serve.go index cb92828..77215c3 100644 --- a/serve.go +++ b/serve.go @@ -1,17 +1,19 @@ package main import ( - "database/sql" "encoding/json" "flag" "fmt" - "math/rand" "net/http" "os" "path" + "strconv" "time" - "github.com/gobuffalo/packr/v2" + packr "github.com/gobuffalo/packr/v2" + + "code.chrissexton.org/cws/happy/email" + "code.chrissexton.org/cws/happy/user" _ "github.com/mattn/go-sqlite3" @@ -27,8 +29,36 @@ var ( salt = flag.String("salt", "happy", "salt for IDs") minHashLen = flag.Int("minHashLen", 4, "minimum ID hash size") develop = flag.Bool("develop", false, "turn on develop mode") + mailAddr = flag.String("mailAddr", "", "email server address") + mailPort = flag.Int("mailPort", 587, "email server port") + mailUser = flag.String("mailUser", "", "email user") + mailPass = flag.String("mailPass", "", "email password") ) +func validateMail() bool { + log.Debug().Str("mailAddr", *mailAddr).Msg("about to look up mail") + if val, ok := os.LookupEnv("MAIL_ADDR"); *mailAddr == "" && ok { + *mailAddr = val + log.Debug().Str("addr", *mailAddr).Str("val", val).Msg("set mailAddr") + } + if val, ok := os.LookupEnv("MAIL_PORT"); *mailPort == 0 && ok { + *mailPort, _ = strconv.Atoi(val) + log.Debug().Int("val", *mailPort).Msg("set mailPort") + } + if val, ok := os.LookupEnv("MAIL_USER"); *mailUser == "" && ok { + *mailUser = val + log.Debug().Str("val", *mailUser).Msg("set mailUser") + } + if val, ok := os.LookupEnv("MAIL_PASS"); *mailPass == "" && ok { + *mailPass = val + log.Debug().Str("val", *mailPass).Msg("set mailPass") + } + if *mailAddr != "" && *mailPort != 0 && *mailUser != "" && *mailPass != "" { + return true + } + return false +} + func main() { flag.Parse() log.Logger = log.Logger.Output(zerolog.ConsoleWriter{Out: os.Stderr}) @@ -60,6 +90,14 @@ func main() { Err(err). Msg("could not create database") } + if validateMail() { + log.Debug().Msg("sending mail") + s.email = email.New(*mailAddr, *mailPort, *mailUser, *mailPass) + u, _ := s.NewUser() + s.email.SendNewUserMail("chris@chrissexton.org", u, "http://happy.chrissexton.org") + } else { + log.Debug().Msg("mail disabled") + } s.serve() } @@ -70,6 +108,7 @@ type server struct { salt string h *hashids.HashID box *packr.Box + email *email.EMailClient } func (s *server) makeDB() error { @@ -141,32 +180,14 @@ func (s *server) populateMoods() error { return tx.Commit() } -func (s *server) recordMood(mood getMoodsResponse, who UserID) error { +func (s *server) recordMood(mood getMoodsResponse, who user.User) error { q := `insert into moods (user_id,mood_category_id,value,time) values (?,?,?,?)` _, err := s.db.Exec(q, who.ID, mood.CategoryID, mood.Value, time.Now().Unix()) return err } -type UserID struct { - db *sqlx.DB - - ID int64 - Email sql.NullString - Verification int64 - DateCreated sql.NullInt64 `db:"dateCreated"` - LastLogin sql.NullInt64 `db:"lastLogin"` - - salt int64 - str string -} - -func (s *server) NewUserID() (UserID, error) { - uid := UserID{ - db: s.db, - DateCreated: sql.NullInt64{time.Now().Unix(), true}, - LastLogin: sql.NullInt64{time.Now().Unix(), true}, - Verification: rand.Int63(), - } +func (s *server) NewUser() (user.User, error) { + uid := user.New(s.db, s.salt, s.h) q := `insert into users (verification,dateCreated) values (?, ?)` res, err := s.db.Exec(q, uid.Verification, uid.DateCreated) if err != nil { @@ -177,16 +198,11 @@ func (s *server) NewUserID() (UserID, error) { return uid, err } uid.ID = id - idstr, err := s.h.EncodeInt64([]int64{id}) - if err != nil { - return uid, err - } - uid.str = idstr return uid, nil } -func (s *server) FromStr(uid, verification string) (UserID, error) { - id := UserID{db: s.db} +func (s *server) FromStr(uid, verification string) (user.User, error) { + id := user.New(s.db, s.salt, s.h) if uid == "" || verification == "" { return id, fmt.Errorf("user ID and verification not given.") } @@ -220,10 +236,6 @@ func (s *server) FromStr(uid, verification string) (UserID, error) { return id, nil } -func (u UserID) String() string { - return u.str -} - type RegisterResponse struct { ID string DateCreated int64 @@ -231,7 +243,7 @@ type RegisterResponse struct { } func (s *server) handlerRegisterCode(w http.ResponseWriter, r *http.Request) { - uid, err := s.NewUserID() + uid, err := s.NewUser() if err != nil { w.WriteHeader(500) log.Error().Err(err).Msg("error from NewUserID") diff --git a/user/user.go b/user/user.go new file mode 100644 index 0000000..b19cfcf --- /dev/null +++ b/user/user.go @@ -0,0 +1,50 @@ +package user + +import ( + "database/sql" + "math/rand" + "time" + + "github.com/speps/go-hashids" + + "github.com/jmoiron/sqlx" +) + +type User struct { + db *sqlx.DB + + ID int64 + Email sql.NullString + Verification int64 + DateCreated sql.NullInt64 `db:"dateCreated"` + LastLogin sql.NullInt64 `db:"lastLogin"` + + salt string + str string +} + +func New(db *sqlx.DB, salt string, h *hashids.HashID) User { + u := User{ + db: db, + salt: salt, + + DateCreated: sql.NullInt64{time.Now().Unix(), true}, + LastLogin: sql.NullInt64{time.Now().Unix(), true}, + Verification: rand.Int63(), + } + u.UpdateID(h) + return u +} + +func (u *User) UpdateID(h *hashids.HashID) error { + idstr, err := h.EncodeInt64([]int64{u.ID}) + if err != nil { + return err + } + u.str = idstr + return nil +} + +func (u User) String() string { + return u.str +}