增加邮件服务功能
This commit is contained in:
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
|||||||
github.com/antonfisher/nested-logrus-formatter v1.3.0
|
github.com/antonfisher/nested-logrus-formatter v1.3.0
|
||||||
github.com/gofrs/uuid v3.3.0+incompatible
|
github.com/gofrs/uuid v3.3.0+incompatible
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
|
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||||
github.com/labstack/echo/v4 v4.1.17
|
github.com/labstack/echo/v4 v4.1.17
|
||||||
github.com/labstack/gommon v0.3.0
|
github.com/labstack/gommon v0.3.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
|
12
go.sum
12
go.sum
@ -107,6 +107,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
|||||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
@ -151,9 +153,7 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
|||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
@ -182,16 +182,12 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
|
|
||||||
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
@ -215,7 +211,6 @@ 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/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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
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/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
@ -300,7 +295,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -308,7 +302,6 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirS
|
|||||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -354,7 +347,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
|||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
@ -14,10 +14,11 @@ func UserCreateEndpoint(c echo.Context) error {
|
|||||||
if err := c.Bind(&item); err != nil {
|
if err := c.Bind(&item); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
password := item.Password
|
||||||
|
|
||||||
var pass []byte
|
var pass []byte
|
||||||
var err error
|
var err error
|
||||||
if pass, err = utils.Encoder.Encode([]byte(item.Password)); err != nil {
|
if pass, err = utils.Encoder.Encode([]byte(password)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
item.Password = string(pass)
|
item.Password = string(pass)
|
||||||
@ -28,6 +29,10 @@ func UserCreateEndpoint(c echo.Context) error {
|
|||||||
if err := model.CreateNewUser(&item); err != nil {
|
if err := model.CreateNewUser(&item); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if item.Mail != "" {
|
||||||
|
go model.SendMail(item.Mail, "[Next Terminal] 注册通知", "你好,"+item.Nickname+"。管理员为你注册了账号:"+item.Username+" 密码:"+password)
|
||||||
|
}
|
||||||
return Success(c, item)
|
return Success(c, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +41,12 @@ func UserPagingEndpoint(c echo.Context) error {
|
|||||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||||
username := c.QueryParam("username")
|
username := c.QueryParam("username")
|
||||||
nickname := c.QueryParam("nickname")
|
nickname := c.QueryParam("nickname")
|
||||||
|
mail := c.QueryParam("mail")
|
||||||
|
|
||||||
order := c.QueryParam("order")
|
order := c.QueryParam("order")
|
||||||
field := c.QueryParam("field")
|
field := c.QueryParam("field")
|
||||||
|
|
||||||
items, total, err := model.FindPageUser(pageIndex, pageSize, username, nickname, order, field)
|
items, total, err := model.FindPageUser(pageIndex, pageSize, username, nickname, mail, order, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -109,6 +115,11 @@ func UserChangePasswordEndpoint(c echo.Context) error {
|
|||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
password := c.QueryParam("password")
|
password := c.QueryParam("password")
|
||||||
|
|
||||||
|
user, err := model.FindUserById(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
passwd, err := utils.Encoder.Encode([]byte(password))
|
passwd, err := utils.Encoder.Encode([]byte(password))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -117,6 +128,11 @@ func UserChangePasswordEndpoint(c echo.Context) error {
|
|||||||
Password: string(passwd),
|
Password: string(passwd),
|
||||||
}
|
}
|
||||||
model.UpdateUserById(u, id)
|
model.UpdateUserById(u, id)
|
||||||
|
|
||||||
|
if user.Mail != "" {
|
||||||
|
go model.SendMail(user.Mail, "[Next Terminal] 密码修改通知", "你好,"+user.Nickname+"。管理员已将你的密码修改为:"+password)
|
||||||
|
}
|
||||||
|
|
||||||
return Success(c, "")
|
return Success(c, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/jordan-wright/email"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"net/smtp"
|
||||||
"next-terminal/pkg/global"
|
"next-terminal/pkg/global"
|
||||||
"next-terminal/pkg/guacd"
|
"next-terminal/pkg/guacd"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SshMode = "ssh-mode"
|
SshMode = "ssh-mode"
|
||||||
|
MailHost = "mail-host"
|
||||||
|
MailPort = "mail-port"
|
||||||
|
MailUsername = "mail-username"
|
||||||
|
MailPassword = "mail-password"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Property struct {
|
type Property struct {
|
||||||
@ -64,3 +71,26 @@ func GetRecordingPath() (string, error) {
|
|||||||
}
|
}
|
||||||
return property.Value, nil
|
return property.Value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendMail(to, subject, text string) {
|
||||||
|
propertiesMap := FindAllPropertiesMap()
|
||||||
|
host := propertiesMap[MailHost]
|
||||||
|
port := propertiesMap[MailPort]
|
||||||
|
username := propertiesMap[MailUsername]
|
||||||
|
password := propertiesMap[MailPassword]
|
||||||
|
|
||||||
|
if host == "" || port == "" || username == "" || password == "" {
|
||||||
|
logrus.Debugf("邮箱信息不完整,跳过发送邮件。")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e := email.NewEmail()
|
||||||
|
e.From = "Next Terminal <" + username + ">"
|
||||||
|
e.To = []string{to}
|
||||||
|
e.Subject = subject
|
||||||
|
e.Text = []byte(text)
|
||||||
|
err := e.Send(host+":"+port, smtp.PlainAuth("", username, password, host))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("邮件发送失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -28,6 +28,8 @@ type UserVo struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
|
TOTPSecret string `json:"totpSecret"`
|
||||||
|
Mail string `json:"mail"`
|
||||||
Online bool `json:"online"`
|
Online bool `json:"online"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Created utils.JsonTime `json:"created"`
|
Created utils.JsonTime `json:"created"`
|
||||||
@ -50,8 +52,8 @@ func FindAllUser() (o []User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindPageUser(pageIndex, pageSize int, username, nickname, order, field string) (o []UserVo, total int64, err error) {
|
func FindPageUser(pageIndex, pageSize int, username, nickname, mail, order, field string) (o []UserVo, total int64, err error) {
|
||||||
db := global.DB.Table("users").Select("users.id,users.username,users.nickname,users.online,users.enabled,users.created,users.type, count(resource_sharers.user_id) as sharer_asset_count").Joins("left join resource_sharers on users.id = resource_sharers.user_id and resource_sharers.resource_type = 'asset'").Group("users.id")
|
db := global.DB.Table("users").Select("users.id,users.username,users.nickname,users.mail,users.online,users.enabled,users.created,users.type, count(resource_sharers.user_id) as sharer_asset_count, users.totp_secret").Joins("left join resource_sharers on users.id = resource_sharers.user_id and resource_sharers.resource_type = 'asset'").Group("users.id")
|
||||||
dbCounter := global.DB.Table("users")
|
dbCounter := global.DB.Table("users")
|
||||||
if len(username) > 0 {
|
if len(username) > 0 {
|
||||||
db = db.Where("users.username like ?", "%"+username+"%")
|
db = db.Where("users.username like ?", "%"+username+"%")
|
||||||
@ -63,6 +65,11 @@ func FindPageUser(pageIndex, pageSize int, username, nickname, order, field stri
|
|||||||
dbCounter = dbCounter.Where("nickname like ?", "%"+nickname+"%")
|
dbCounter = dbCounter.Where("nickname like ?", "%"+nickname+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(mail) > 0 {
|
||||||
|
db = db.Where("users.mail like ?", "%"+mail+"%")
|
||||||
|
dbCounter = dbCounter.Where("mail like ?", "%"+mail+"%")
|
||||||
|
}
|
||||||
|
|
||||||
err = dbCounter.Count(&total).Error
|
err = dbCounter.Count(&total).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
@ -86,6 +93,14 @@ func FindPageUser(pageIndex, pageSize int, username, nickname, order, field stri
|
|||||||
if o == nil {
|
if o == nil {
|
||||||
o = make([]UserVo, 0)
|
o = make([]UserVo, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(o); i++ {
|
||||||
|
if o[i].TOTPSecret == "" || o[i].TOTPSecret == "-" {
|
||||||
|
o[i].TOTPSecret = "0"
|
||||||
|
} else {
|
||||||
|
o[i].TOTPSecret = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +318,7 @@ class LoginLog extends Component {
|
|||||||
onSearch={this.handleSearchByNickname}
|
onSearch={this.handleSearchByNickname}
|
||||||
onChange={this.handleChangeByUserId}
|
onChange={this.handleChangeByUserId}
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
|
allowClear
|
||||||
>
|
>
|
||||||
{userOptions}
|
{userOptions}
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -379,6 +379,7 @@ class OfflineSession extends Component {
|
|||||||
onSearch={this.handleSearchByNickname}
|
onSearch={this.handleSearchByNickname}
|
||||||
onChange={this.handleChangeByUserId}
|
onChange={this.handleChangeByUserId}
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
|
allowClear
|
||||||
>
|
>
|
||||||
{userOptions}
|
{userOptions}
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -374,6 +374,7 @@ class OnlineSession extends Component {
|
|||||||
onSearch={this.handleSearchByNickname}
|
onSearch={this.handleSearchByNickname}
|
||||||
onChange={this.handleChangeByUserId}
|
onChange={this.handleChangeByUserId}
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
|
allowClear
|
||||||
>
|
>
|
||||||
{userOptions}
|
{userOptions}
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -42,6 +42,7 @@ class Setting extends Component {
|
|||||||
sshSettingFormRef = React.createRef();
|
sshSettingFormRef = React.createRef();
|
||||||
vncSettingFormRef = React.createRef();
|
vncSettingFormRef = React.createRef();
|
||||||
otherSettingFormRef = React.createRef();
|
otherSettingFormRef = React.createRef();
|
||||||
|
mailSettingFormRef = React.createRef();
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.getProperties();
|
this.getProperties();
|
||||||
@ -98,6 +99,10 @@ class Setting extends Component {
|
|||||||
if (this.otherSettingFormRef.current) {
|
if (this.otherSettingFormRef.current) {
|
||||||
this.otherSettingFormRef.current.setFieldsValue(properties)
|
this.otherSettingFormRef.current.setFieldsValue(properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.mailSettingFormRef.current) {
|
||||||
|
this.mailSettingFormRef.current.setFieldsValue(properties)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error(result['message']);
|
message.error(result['message']);
|
||||||
}
|
}
|
||||||
@ -561,6 +566,77 @@ class Setting extends Component {
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item {...formTailLayout}>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
更新
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="邮箱配置" key="mail">
|
||||||
|
<Title level={3}>Guacd 服务配置</Title>
|
||||||
|
<Form ref={this.mailSettingFormRef} name="password" onFinish={this.changeProperties}
|
||||||
|
layout="vertical">
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="mail-host"
|
||||||
|
label="邮件服务器地址"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: false,
|
||||||
|
message: '邮件服务器地址',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="请输入邮件服务器地址"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="mail-port"
|
||||||
|
label="邮件服务器端口"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: false,
|
||||||
|
message: '邮件服务器地址',
|
||||||
|
min: 1,
|
||||||
|
max: 65535
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input type='number' placeholder="请输入邮件服务器地址"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="mail-username"
|
||||||
|
label="邮箱账号"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: false,
|
||||||
|
type: "email",
|
||||||
|
message: '请输入正确的邮箱账号',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input type='email' placeholder="请输入邮箱账号"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="mail-password"
|
||||||
|
label="邮箱密码"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: false,
|
||||||
|
message: '邮箱密码',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input type='password' placeholder="请输入邮箱密码"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item {...formTailLayout}>
|
<Form.Item {...formTailLayout}>
|
||||||
<Button type="primary" htmlType="submit">
|
<Button type="primary" htmlType="submit">
|
||||||
更新
|
更新
|
||||||
|
@ -25,9 +25,10 @@ import UserModal from "./UserModal";
|
|||||||
import request from "../../common/request";
|
import request from "../../common/request";
|
||||||
import {message} from "antd/es";
|
import {message} from "antd/es";
|
||||||
import {
|
import {
|
||||||
|
CheckCircleOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownOutlined,
|
DownOutlined,
|
||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined, InsuranceOutlined,
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
@ -58,6 +59,7 @@ class User extends Component {
|
|||||||
|
|
||||||
inputRefOfNickname = React.createRef();
|
inputRefOfNickname = React.createRef();
|
||||||
inputRefOfUsername = React.createRef();
|
inputRefOfUsername = React.createRef();
|
||||||
|
inputRefOfMail = React.createRef();
|
||||||
changePasswordFormRef = React.createRef()
|
changePasswordFormRef = React.createRef()
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -234,6 +236,17 @@ class User extends Component {
|
|||||||
this.loadTableData(query);
|
this.loadTableData(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleSearchByMail = mail => {
|
||||||
|
let query = {
|
||||||
|
...this.state.queryParams,
|
||||||
|
'pageIndex': 1,
|
||||||
|
'pageSize': this.state.queryParams.pageSize,
|
||||||
|
'mail': mail,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadTableData(query);
|
||||||
|
};
|
||||||
|
|
||||||
batchDelete = async () => {
|
batchDelete = async () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
delBtnLoading: true
|
delBtnLoading: true
|
||||||
@ -327,7 +340,22 @@ class User extends Component {
|
|||||||
} else {
|
} else {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: '邮箱',
|
||||||
|
dataIndex: 'mail',
|
||||||
|
key: 'mail',
|
||||||
|
}, {
|
||||||
|
title: '二次认证',
|
||||||
|
dataIndex: 'totpSecret',
|
||||||
|
key: 'totpSecret',
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
if (text === '1') {
|
||||||
|
return <Tag icon={<InsuranceOutlined />} color="success">开启</Tag>;
|
||||||
|
}else {
|
||||||
|
return <Tag icon={<ExclamationCircleOutlined />} color="warning">关闭</Tag>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
title: '在线状态',
|
title: '在线状态',
|
||||||
@ -394,6 +422,7 @@ class User extends Component {
|
|||||||
let result = await request.post(`/users/${record['id']}/reset-totp`);
|
let result = await request.post(`/users/${record['id']}/reset-totp`);
|
||||||
if (result['code'] === 1) {
|
if (result['code'] === 1) {
|
||||||
message.success('操作成功', 3);
|
message.success('操作成功', 3);
|
||||||
|
this.loadTableData();
|
||||||
} else {
|
} else {
|
||||||
message.error(result['message'], 10);
|
message.error(result['message'], 10);
|
||||||
}
|
}
|
||||||
@ -414,7 +443,14 @@ class User extends Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button type="link" size='small'
|
<Button type="link" size='small'
|
||||||
onClick={() => this.showModal('更新用户', record)}>编辑</Button>
|
onClick={async () => {
|
||||||
|
let result = await request.get(`/users/${record['id']}`);
|
||||||
|
if (result['code'] !== 1) {
|
||||||
|
message.error(result['message']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showModal('更新用户', result['data']);
|
||||||
|
}}>编辑</Button>
|
||||||
<Dropdown overlay={menu}>
|
<Dropdown overlay={menu}>
|
||||||
<Button type="link" size='small'>
|
<Button type="link" size='small'>
|
||||||
更多 <DownOutlined/>
|
更多 <DownOutlined/>
|
||||||
@ -474,11 +510,19 @@ class User extends Component {
|
|||||||
onSearch={this.handleSearchByUsername}
|
onSearch={this.handleSearchByUsername}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Search
|
||||||
|
ref={this.inputRefOfMail}
|
||||||
|
placeholder="邮箱"
|
||||||
|
allowClear
|
||||||
|
onSearch={this.handleSearchByMail}
|
||||||
|
/>
|
||||||
|
|
||||||
<Tooltip title='重置查询'>
|
<Tooltip title='重置查询'>
|
||||||
|
|
||||||
<Button icon={<UndoOutlined/>} onClick={() => {
|
<Button icon={<UndoOutlined/>} onClick={() => {
|
||||||
this.inputRefOfUsername.current.setValue('');
|
this.inputRefOfUsername.current.setValue('');
|
||||||
this.inputRefOfNickname.current.setValue('');
|
this.inputRefOfNickname.current.setValue('');
|
||||||
|
this.inputRefOfMail.current.setValue('');
|
||||||
this.loadTableData({pageIndex: 1, pageSize: 10})
|
this.loadTableData({pageIndex: 1, pageSize: 10})
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ const UserModal = ({title, visible, handleOk, handleCancel, confirmLoading, mode
|
|||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item label="邮箱账号" name="mail" rules={[{required: false, type: "email", message: '请输入正确的邮箱账号',},]}>
|
||||||
|
<Input type='email' placeholder="请输入邮箱账号"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
{
|
{
|
||||||
title.indexOf('新增') > -1 ?
|
title.indexOf('新增') > -1 ?
|
||||||
(<Form.Item label="登录密码" name='password' rules={[{required: true, message: '请输入登录密码'}]}>
|
(<Form.Item label="登录密码" name='password' rules={[{required: true, message: '请输入登录密码'}]}>
|
||||||
|
Reference in New Issue
Block a user