Compare commits

..

14 Commits

Author SHA1 Message Date
Yaodong Yu
e21087aa50 feat: refactor reset password api and forgetPage.js (#1601) 2023-03-01 15:57:42 +08:00
longxu0509
b38f2218a3 feat: add basic MySQL sync functionality (#1575)
* feat: add sync module to bi-sync mysql

* feat: fix the delay problem

* feat: fix go mod

* feat: fix the varchar(100) parse error

* fix: fix go.mod space inconsistency

* fix: fix go.mod space inconsistency

* fix: use sql builder instead of concatenation

* fix: remove serverId

* fix: fix file is not `gofumpt`-ed (gofumpt) error
2023-02-28 16:48:06 +08:00
Yaodong Yu
afd3c4ed25 fix: fix bug form country code init error (#1591) 2023-02-27 22:07:28 +08:00
Yaodong Yu
5caceb4ae2 feat: fix bug that signup country code is undefined (#1590)
* feat: fix signup country code is undefined

* refactor: valid phone number in CN
2023-02-27 20:10:59 +08:00
Gucheng Wang
f5672357e6 fix resetting phone bug 2023-02-25 15:46:54 +08:00
Gucheng Wang
181e7c8c7d Refactor out getCountryCodeOption() 2023-02-25 15:25:47 +08:00
Gucheng Wang
36c5a9d09b Sort country list 2023-02-25 15:08:08 +08:00
Gucheng Wang
9acb3c499e Can search country code 2023-02-25 14:57:23 +08:00
Gucheng Wang
0e9a3b0f30 don't update provider in preview 2023-02-25 12:31:08 +08:00
Gucheng Wang
d104a292e7 fix normal user phone edit control 2023-02-25 11:47:34 +08:00
Gucheng Wang
8fbd5b1a74 disable demo prompt for get-organizations API 2023-02-25 11:01:48 +08:00
Gucheng Wang
f5a05ac534 improve application homepage 2023-02-25 10:50:50 +08:00
Gucheng Wang
05fade1d05 fix role list link error 2023-02-25 09:39:19 +08:00
Gucheng Wang
8aefa02036 fix message length 2023-02-25 08:36:24 +08:00
39 changed files with 1026 additions and 491 deletions

View File

@@ -80,7 +80,7 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
p, built-in, *, *, *, *, * p, built-in, *, *, *, *, *
p, app, *, *, *, *, * p, app, *, *, *, *, *
p, *, *, POST, /api/signup, *, * p, *, *, POST, /api/signup, *, *
p, *, *, POST, /api/get-email-and-phone, *, * p, *, *, GET, /api/get-email-and-phone, *, *
p, *, *, POST, /api/login, *, * p, *, *, POST, /api/login, *, *
p, *, *, GET, /api/get-app-login, *, * p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, * p, *, *, POST, /api/logout, *, *

View File

@@ -231,24 +231,20 @@ func (c *ApiController) DeleteUser() {
// @Param username formData string true "The username of the user" // @Param username formData string true "The username of the user"
// @Param organization formData string true "The organization of the user" // @Param organization formData string true "The organization of the user"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /get-email-and-phone [post] // @router /get-email-and-phone [get]
func (c *ApiController) GetEmailAndPhone() { func (c *ApiController) GetEmailAndPhone() {
var form RequestForm organization := c.Ctx.Request.Form.Get("organization")
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form) username := c.Ctx.Request.Form.Get("username")
if err != nil {
c.ResponseError(err.Error())
return
}
user := object.GetUserByFields(form.Organization, form.Username) user := object.GetUserByFields(organization, username)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username))) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(organization, username)))
return return
} }
respUser := object.User{Name: user.Name} respUser := object.User{Name: user.Name}
var contentType string var contentType string
switch form.Username { switch username {
case user.Email: case user.Email:
contentType = "email" contentType = "email"
respUser.Email = user.Email respUser.Email = user.Email
@@ -281,7 +277,7 @@ func (c *ApiController) SetPassword() {
newPassword := c.Ctx.Request.Form.Get("newPassword") newPassword := c.Ctx.Request.Form.Get("newPassword")
requestUserId := c.GetSessionUsername() requestUserId := c.GetSessionUsername()
userId := fmt.Sprintf("%s/%s", userOwner, userName) userId := util.GetId(userOwner, userName)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true, c.GetAcceptLanguage()) hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true, c.GetAcceptLanguage())
if !hasPermission { if !hasPermission {
@@ -311,8 +307,7 @@ func (c *ApiController) SetPassword() {
targetUser.Password = newPassword targetUser.Password = newPassword
object.SetUserField(targetUser, "password", targetUser.Password) object.SetUserField(targetUser, "password", targetUser.Password)
c.Data["json"] = Response{Status: "ok"} c.ResponseOk()
c.ServeJSON()
} }
// CheckUserPassword // CheckUserPassword

8
go.mod
View File

@@ -3,8 +3,10 @@ module github.com/casdoor/casdoor
go 1.16 go 1.16
require ( require (
github.com/Masterminds/squirrel v1.5.3
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 // indirect
github.com/aws/aws-sdk-go v1.44.4 github.com/aws/aws-sdk-go v1.44.4
github.com/beego/beego v1.12.11 github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
@@ -18,12 +20,13 @@ require (
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/forestmgy/ldapserver v1.1.0 github.com/forestmgy/ldapserver v1.1.0
github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-mysql-org/go-mysql v1.7.0
github.com/go-pay/gopay v1.5.72 github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-cmp v0.5.8 // indirect
github.com/google/uuid v1.2.0 github.com/google/uuid v1.3.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v1.2.21 github.com/lestrrat-go/jwx v1.2.21
github.com/lib/pq v1.8.0 github.com/lib/pq v1.8.0
@@ -37,6 +40,7 @@ require (
github.com/russellhaering/goxmldsig v1.1.1 github.com/russellhaering/goxmldsig v1.1.1
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx v1.0.5

81
go.sum
View File

@@ -58,6 +58,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -68,8 +70,9 @@ github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90v
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc= github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075 h1:Z0SzZttfYI/raZ5O9WF3cezZJTSW4Yz4Kow9uWdyRwg=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 h1:8lIVcOlHW+fKCGMEf6nuGTTEFOt/EZJPZ8oq0kTlhGk=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
@@ -83,6 +86,8 @@ github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkY
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -118,6 +123,9 @@ github.com/couchbase/gomemcached v0.1.2-0.20201224031647-c432ccf49f32/go.mod h1:
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -159,6 +167,8 @@ github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyDe9tvqI=
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw= github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
@@ -171,8 +181,9 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E= github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@@ -247,8 +258,9 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -276,6 +288,7 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
@@ -304,6 +317,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
@@ -319,6 +336,7 @@ github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abR
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
@@ -363,8 +381,19 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 h1:k2BbABz9+TNpYRwsCCFS8pEEnFVOdbgEjL/kTlLuzZQ=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d h1:1DyyRrgYeNjqPkgjrdEsaIbX+kHpuTTk5ZOCtrcRFcQ=
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d/go.mod h1:ElJiub4lRy6UZDb+0JHDkGEdr6aOli+ykhyej7VCLoI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -412,7 +441,14 @@ github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed h1:KMgQoLJGCq1IoZpLZE3AIffh9veYWoVlsvA4ib55TMM=
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -449,6 +485,10 @@ github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U= github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U=
github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE= github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA= github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4= github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
@@ -475,6 +515,19 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -493,6 +546,7 @@ golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -514,6 +568,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -665,6 +720,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -693,6 +750,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -794,9 +852,12 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -823,26 +884,38 @@ modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9J
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878= modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA= modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA=
modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY= modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8= modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8=
modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM= modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/parser v1.0.0/go.mod h1:H20AntYJ2cHHL6MHthJ8LZzXCdDCHMWt1KZXtIMjejA=
modernc.org/parser v1.0.2/go.mod h1:TXNq3HABP3HMaqLK7brD1fLA/LfN0KS6JxZn71QdDqs=
modernc.org/scanner v1.0.1/go.mod h1:OIzD2ZtjYk6yTuyqZr57FmifbM9fIH74SumloSsajuE=
modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtxM=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY= modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU= modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs= modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs=
modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc= modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/y v1.0.1/go.mod h1:Ho86I+LVHEI+LYXoUKlmOMAM1JTXOCfj8qi1T8PsClE=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc= modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=

View File

@@ -43,7 +43,7 @@ type Payment struct {
PayUrl string `xorm:"varchar(2000)" json:"payUrl"` PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"` ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
State string `xorm:"varchar(100)" json:"state"` State string `xorm:"varchar(100)" json:"state"`
Message string `xorm:"varchar(1000)" json:"message"` Message string `xorm:"varchar(2000)" json:"message"`
PersonName string `xorm:"varchar(100)" json:"personName"` PersonName string `xorm:"varchar(100)" json:"personName"`
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"` PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`

View File

@@ -449,7 +449,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
if len(columns) == 0 { if len(columns) == 0 {
columns = []string{ columns = []string{
"owner", "display_name", "avatar", "owner", "display_name", "avatar",
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application", "location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"signin_wrong_times", "last_signin_wrong_time", "signin_wrong_times", "last_signin_wrong_time",
} }

View File

@@ -53,9 +53,11 @@ func GetUserByFields(organization string, field string) *User {
} }
// check email // check email
user = GetUserByField(organization, "email", field) if strings.Contains(field, "@") {
if user != nil { user = GetUserByField(organization, "email", field)
return user if user != nil {
return user
}
} }
// check phone // check phone

View File

@@ -112,7 +112,7 @@ func initAPI() {
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword") beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword") beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "POST:GetEmailAndPhone") beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode") beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha") beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone") beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")

View File

@@ -339,6 +339,42 @@
} }
} }
}, },
"/api/add-session": {
"post": {
"tags": [
"Session API"
],
"description": "Add session for one user in one application. If there are other existing sessions, join the session into the list.",
"operationId": "ApiController.AddSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "sessionId",
"description": "sessionId to be added",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/add-syncer": { "/api/add-syncer": {
"post": { "post": {
"tags": [ "tags": [
@@ -889,13 +925,13 @@
"tags": [ "tags": [
"Session API" "Session API"
], ],
"description": "Delete session by userId", "description": "Delete session for one user in one application.",
"operationId": "ApiController.DeleteSession", "operationId": "ApiController.DeleteSession",
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
"name": "id", "name": "id",
"description": "The id ( owner/name )(owner/name) of user.", "description": "The id(organization/application/user) of session",
"required": true, "required": true,
"type": "string" "type": "string"
} }
@@ -1233,7 +1269,7 @@
} }
}, },
"/api/get-email-and-phone": { "/api/get-email-and-phone": {
"post": { "get": {
"tags": [ "tags": [
"User API" "User API"
], ],
@@ -1306,7 +1342,7 @@
} }
}, },
"/api/get-ldap": { "/api/get-ldap": {
"post": { "get": {
"tags": [ "tags": [
"Account API" "Account API"
], ],
@@ -1322,7 +1358,7 @@
} }
}, },
"/api/get-ldaps": { "/api/get-ldaps": {
"post": { "get": {
"tags": [ "tags": [
"Account API" "Account API"
], ],
@@ -1884,12 +1920,41 @@
} }
} }
}, },
"/api/get-session": {
"get": {
"tags": [
"Session API"
],
"description": "Get session for one user in one application.",
"operationId": "ApiController.GetSingleSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/get-sessions": { "/api/get-sessions": {
"get": { "get": {
"tags": [ "tags": [
"Session API" "Session API"
], ],
"description": "Get organization user sessions", "description": "Get organization user sessions.",
"operationId": "ApiController.GetSessions", "operationId": "ApiController.GetSessions",
"parameters": [ "parameters": [
{ {
@@ -2356,6 +2421,42 @@
} }
} }
}, },
"/api/is-session-duplicated": {
"get": {
"tags": [
"Session API"
],
"description": "Check if there are other different sessions for one user in one application.",
"operationId": "ApiController.IsSessionDuplicated",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "sessionId",
"description": "sessionId to be checked",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/login": { "/api/login": {
"post": { "post": {
"tags": [ "tags": [
@@ -3224,6 +3325,35 @@
} }
} }
}, },
"/api/update-session": {
"post": {
"tags": [
"Session API"
],
"description": "Update session for one user in one application.",
"operationId": "ApiController.UpdateSession",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id(organization/application/user) of session",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/api/update-syncer": { "/api/update-syncer": {
"post": { "post": {
"tags": [ "tags": [
@@ -3505,11 +3635,11 @@
} }
}, },
"definitions": { "definitions": {
"2346.0xc0001ce990.false": { "2346.0xc000278ab0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"2381.0xc0001ce9c0.false": { "2381.0xc000278ae0.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
@@ -3566,6 +3696,9 @@
"code": { "code": {
"type": "string" "type": "string"
}, },
"countryCode": {
"type": "string"
},
"email": { "email": {
"type": "string" "type": "string"
}, },
@@ -3599,9 +3732,6 @@
"phoneCode": { "phoneCode": {
"type": "string" "type": "string"
}, },
"phonePrefix": {
"type": "string"
},
"provider": { "provider": {
"type": "string" "type": "string"
}, },
@@ -3636,10 +3766,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2346.0xc0001ce990.false" "$ref": "#/definitions/2346.0xc000278ab0.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2381.0xc0001ce9c0.false" "$ref": "#/definitions/2381.0xc000278ae0.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@@ -4091,6 +4221,12 @@
"$ref": "#/definitions/object.AccountItem" "$ref": "#/definitions/object.AccountItem"
} }
}, },
"countryCodes": {
"type": "array",
"items": {
"type": "string"
}
},
"createdTime": { "createdTime": {
"type": "string" "type": "string"
}, },
@@ -4137,9 +4273,6 @@
"passwordType": { "passwordType": {
"type": "string" "type": "string"
}, },
"phonePrefix": {
"type": "string"
},
"tags": { "tags": {
"type": "array", "type": "array",
"items": { "items": {
@@ -4906,6 +5039,9 @@
"cloudfoundry": { "cloudfoundry": {
"type": "string" "type": "string"
}, },
"countryCode": {
"type": "string"
},
"createdIp": { "createdIp": {
"type": "string" "type": "string"
}, },

View File

@@ -218,6 +218,30 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/add-session:
post:
tags:
- Session API
description: Add session for one user in one application. If there are other existing sessions, join the session into the list.
operationId: ApiController.AddSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
- in: query
name: sessionId
description: sessionId to be added
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/add-syncer: /api/add-syncer:
post: post:
tags: tags:
@@ -574,12 +598,12 @@ paths:
post: post:
tags: tags:
- Session API - Session API
description: Delete session by userId description: Delete session for one user in one application.
operationId: ApiController.DeleteSession operationId: ApiController.DeleteSession
parameters: parameters:
- in: query - in: query
name: id name: id
description: The id ( owner/name )(owner/name) of user. description: The id(organization/application/user) of session
required: true required: true
type: string type: string
responses: responses:
@@ -799,7 +823,7 @@ paths:
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
/api/get-email-and-phone: /api/get-email-and-phone:
post: get:
tags: tags:
- User API - User API
description: get email and phone by username description: get email and phone by username
@@ -847,7 +871,7 @@ paths:
items: items:
$ref: '#/definitions/object.User' $ref: '#/definitions/object.User'
/api/get-ldap: /api/get-ldap:
post: get:
tags: tags:
- Account API - Account API
operationId: ApiController.GetLdap operationId: ApiController.GetLdap
@@ -857,7 +881,7 @@ paths:
- Account API - Account API
operationId: ApiController.GetLdapser operationId: ApiController.GetLdapser
/api/get-ldaps: /api/get-ldaps:
post: get:
tags: tags:
- Account API - Account API
operationId: ApiController.GetLdaps operationId: ApiController.GetLdaps
@@ -1224,11 +1248,30 @@ paths:
type: array type: array
items: items:
$ref: '#/definitions/object.Role' $ref: '#/definitions/object.Role'
/api/get-session:
get:
tags:
- Session API
description: Get session for one user in one application.
operationId: ApiController.GetSingleSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/get-sessions: /api/get-sessions:
get: get:
tags: tags:
- Session API - Session API
description: Get organization user sessions description: Get organization user sessions.
operationId: ApiController.GetSessions operationId: ApiController.GetSessions
parameters: parameters:
- in: query - in: query
@@ -1535,6 +1578,30 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/is-session-duplicated:
get:
tags:
- Session API
description: Check if there are other different sessions for one user in one application.
operationId: ApiController.IsSessionDuplicated
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
- in: query
name: sessionId
description: sessionId to be checked
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/login: /api/login:
post: post:
tags: tags:
@@ -2110,6 +2177,25 @@ paths:
description: The Response object description: The Response object
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
/api/update-session:
post:
tags:
- Session API
description: Update session for one user in one application.
operationId: ApiController.UpdateSession
parameters:
- in: query
name: id
description: The id(organization/application/user) of session
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
type: string
/api/update-syncer: /api/update-syncer:
post: post:
tags: tags:
@@ -2293,10 +2379,10 @@ paths:
schema: schema:
$ref: '#/definitions/Response' $ref: '#/definitions/Response'
definitions: definitions:
2346.0xc0001ce990.false: 2346.0xc000278ab0.false:
title: "false" title: "false"
type: object type: object
2381.0xc0001ce9c0.false: 2381.0xc000278ae0.false:
title: "false" title: "false"
type: object type: object
Response: Response:
@@ -2336,6 +2422,8 @@ definitions:
type: string type: string
code: code:
type: string type: string
countryCode:
type: string
email: email:
type: string type: string
emailCode: emailCode:
@@ -2358,8 +2446,6 @@ definitions:
type: string type: string
phoneCode: phoneCode:
type: string type: string
phonePrefix:
type: string
provider: provider:
type: string type: string
redirectUri: redirectUri:
@@ -2383,9 +2469,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2346.0xc0001ce990.false' $ref: '#/definitions/2346.0xc000278ab0.false'
data2: data2:
$ref: '#/definitions/2381.0xc0001ce9c0.false' $ref: '#/definitions/2381.0xc000278ae0.false'
msg: msg:
type: string type: string
name: name:
@@ -2689,6 +2775,10 @@ definitions:
type: array type: array
items: items:
$ref: '#/definitions/object.AccountItem' $ref: '#/definitions/object.AccountItem'
countryCodes:
type: array
items:
type: string
createdTime: createdTime:
type: string type: string
defaultApplication: defaultApplication:
@@ -2720,8 +2810,6 @@ definitions:
type: string type: string
passwordType: passwordType:
type: string type: string
phonePrefix:
type: string
tags: tags:
type: array type: array
items: items:
@@ -3237,6 +3325,8 @@ definitions:
type: string type: string
cloudfoundry: cloudfoundry:
type: string type: string
countryCode:
type: string
createdIp: createdIp:
type: string type: string
createdTime: createdTime:

187
sync/bi_sync_mysql.go Normal file
View File

@@ -0,0 +1,187 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sync
import (
"fmt"
"github.com/go-mysql-org/go-mysql/canal"
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/replication"
"github.com/siddontang/go-log/log"
"github.com/xorm-io/xorm"
)
var (
dataSourceName1 string
dataSourceName2 string
engin1 *xorm.Engine
engin2 *xorm.Engine
)
func InitConfig() *canal.Config {
// init dataSource
dataSourceName1 = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username1, password1, host1, port1, database1)
dataSourceName2 = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username2, password2, host2, port2, database2)
// create engine
engin1, _ = CreateEngine(dataSourceName1)
engin2, _ = CreateEngine(dataSourceName2)
log.Info("init engine success…")
// config canal
cfg := canal.NewDefaultConfig()
cfg.Addr = fmt.Sprintf("%s:%d", host1, port1)
cfg.Password = password1
cfg.User = username1
// We only care table in database1
cfg.Dump.TableDB = database1
// cfg.Dump.Tables = []string{"user"}
log.Info("config canal success…")
return cfg
}
func StartBinlogSync() error {
// init config
config := InitConfig()
c, err := canal.NewCanal(config)
pos, err := c.GetMasterPos()
if err != nil {
return err
}
// Register a handler to handle RowsEvent
c.SetEventHandler(&MyEventHandler{})
// Start canal
c.RunFrom(pos)
return nil
}
type MyEventHandler struct {
canal.DummyEventHandler
}
func OnTableChanged(header *replication.EventHeader, schema string, table string) error {
log.Info("table changed event")
return nil
}
func (h *MyEventHandler) onDDL(header *replication.EventHeader, nextPos mysql.Position, queryEvent *replication.QueryEvent) error {
log.Info("into DDL event")
return nil
}
func (h *MyEventHandler) OnRow(e *canal.RowsEvent) error {
length := len(e.Table.Columns)
columnNames := make([]string, length)
oldColumnValue := make([]interface{}, length)
newColumnValue := make([]interface{}, length)
isChar := make([]bool, len(e.Table.Columns))
for i, col := range e.Table.Columns {
columnNames[i] = col.Name
if col.Type <= 2 {
isChar[i] = false
} else {
isChar[i] = true
}
}
switch e.Action {
case canal.UpdateAction:
for i, row := range e.Rows {
for j, item := range row {
if i%2 == 0 {
if isChar[j] == true {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
}
} else {
if isChar[j] == true {
newColumnValue[j] = fmt.Sprintf("%s", item)
} else {
newColumnValue[j] = fmt.Sprintf("%d", item)
}
}
}
if i%2 == 1 {
updateSql, args, err := GetUpdateSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue, oldColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(updateSql, args...)
if err != nil {
return err
}
log.Info(updateSql, args, res)
}
}
case canal.DeleteAction:
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
}
}
deleteSql, args, err := GetDeleteSql(e.Table.Schema, e.Table.Name, columnNames, oldColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(deleteSql, args...)
if err != nil {
return err
}
log.Info(deleteSql, args, res)
}
case canal.InsertAction:
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
newColumnValue[j] = fmt.Sprintf("%s", item)
} else {
newColumnValue[j] = fmt.Sprintf("%d", item)
}
}
insertSql, args, err := GetInsertSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(insertSql, args...)
if err != nil {
return err
}
log.Info(insertSql, args, res)
}
default:
log.Infof("%v", e.String())
}
return nil
}
func (h *MyEventHandler) String() string {
return "MyEventHandler"
}

17
sync/conf.go Normal file
View File

@@ -0,0 +1,17 @@
package sync
var (
host1 = "127.0.0.1"
port1 = 3306
username1 = "root"
password1 = "123456"
database1 = "db"
)
var (
host2 = "127.0.0.1"
port2 = 3306
username2 = "root"
password2 = "123456"
database2 = "db"
)

72
sync/utils.go Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sync
import (
"log"
"github.com/Masterminds/squirrel"
"github.com/xorm-io/xorm"
)
func GetUpdateSql(schemaName string, tableName string, columnNames []string, newColumnVal []interface{}, oldColumnVal []interface{}) (string, []interface{}, error) {
updateSql := squirrel.Update(schemaName + "." + tableName)
for i, columnName := range columnNames {
updateSql = updateSql.Set(columnName, newColumnVal[i])
}
for i, columnName := range columnNames {
updateSql = updateSql.Where(squirrel.Eq{columnName: oldColumnVal[i]})
}
sql, args, err := updateSql.ToSql()
if err != nil {
return "", nil, err
}
return sql, args, nil
}
func GetInsertSql(schemaName string, tableName string, columnNames []string, columnValue []interface{}) (string, []interface{}, error) {
insertSql := squirrel.Insert(schemaName + "." + tableName).Columns(columnNames...).Values(columnValue...)
return insertSql.ToSql()
}
func GetDeleteSql(schemaName string, tableName string, columnNames []string, columnValue []interface{}) (string, []interface{}, error) {
deleteSql := squirrel.Delete(schemaName + "." + tableName)
for i, columnName := range columnNames {
deleteSql = deleteSql.Where(squirrel.Eq{columnName: columnValue[i]})
}
return deleteSql.ToSql()
}
func CreateEngine(dataSourceName string) (*xorm.Engine, error) {
engine, err := xorm.NewEngine("mysql", dataSourceName)
if err != nil {
return nil, err
}
// ping mysql
err = engine.Ping()
if err != nil {
return nil, err
}
log.Println("mysql connection success……")
return engine, nil
}

View File

@@ -41,7 +41,7 @@ func IsPhoneValid(phone string, countryCode string) bool {
} }
func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool { func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
return !ContainsString(allowRegions, countryCode) return ContainsString(allowRegions, countryCode)
} }
func GetE164Number(phone string, countryCode string) (string, bool) { func GetE164Number(phone string, countryCode string) (string, bool) {

View File

@@ -184,20 +184,19 @@ class OrganizationEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Supported country code"), i18next.t("general:Supported country code - Tooltip"))} : {Setting.getLabel(i18next.t("general:Supported country codes"), i18next.t("general:Supported country codes - Tooltip"))} :
</Col> </Col>
<Col span={22} > <Col span={22} >
<Select virtual={false} mode={"multiple"} style={{width: "100%"}} value={this.state.organization.countryCodes ?? []} <Select virtual={false} mode={"multiple"} style={{width: "100%"}} value={this.state.organization.countryCodes ?? []}
options={Setting.getCountriesData().map(country => { onChange={value => {
return Setting.getOption(
<>
{Setting.countryFlag(country)}
{`${country.name} +${country.phone}`}
</>,
country.code);
})} onChange={value => {
this.updateOrganizationField("countryCodes", value); this.updateOrganizationField("countryCodes", value);
}} /> }}
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
>
{
Setting.getCountryCodeData().map((country) => Setting.getCountryCodeOption(country))
}
</Select>
</Col> </Col>
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >

View File

@@ -37,7 +37,7 @@ class OrganizationListPage extends BaseListPage {
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`, defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
defaultApplication: "", defaultApplication: "",
tags: [], tags: [],
languages: ["en", "zh", "es", "fr", "de", "ja", "ko", "ru", "vi"], languages: Setting.Countries.map(item => item.key),
masterPassword: "", masterPassword: "",
enableSoftDeletion: false, enableSoftDeletion: false,
isProfilePublic: true, isProfilePublic: true,

View File

@@ -25,7 +25,7 @@ export const ResetModal = (props) => {
const [confirmLoading, setConfirmLoading] = React.useState(false); const [confirmLoading, setConfirmLoading] = React.useState(false);
const [dest, setDest] = React.useState(""); const [dest, setDest] = React.useState("");
const [code, setCode] = React.useState(""); const [code, setCode] = React.useState("");
const {buttonText, destType, application} = props; const {buttonText, destType, application, account} = props;
const showModal = () => { const showModal = () => {
setVisible(true); setVisible(true);
@@ -87,7 +87,7 @@ export const ResetModal = (props) => {
<Row style={{width: "100%", marginBottom: "20px"}}> <Row style={{width: "100%", marginBottom: "20px"}}>
<Input <Input
addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")} addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")}
prefix={destType === "email" ? <MailOutlined /> : <PhoneOutlined />} prefix={destType === "email" ? <React.Fragment><MailOutlined />&nbsp;&nbsp;</React.Fragment> : (<React.Fragment><PhoneOutlined />&nbsp;&nbsp;{`+${Setting.getCountryCode(account.countryCode)}`}&nbsp;</React.Fragment>)}
placeholder={placeholder} placeholder={placeholder}
onChange={e => setDest(e.target.value)} onChange={e => setDest(e.target.value)}
/> />

View File

@@ -82,7 +82,7 @@ class RoleListPage extends BaseListPage {
...this.getColumnSearchProps("name"), ...this.getColumnSearchProps("name"),
render: (text, record, index) => { render: (text, record, index) => {
return ( return (
<Link to={`/roles/${text}`}> <Link to={`/roles/${record.owner}/${record.name}`}>
{text} {text}
</Link> </Link>
); );

View File

@@ -41,17 +41,15 @@ class SelectRegionBox extends React.Component {
defaultValue={this.props.defaultValue || undefined} defaultValue={this.props.defaultValue || undefined}
placeholder="Please select country/region" placeholder="Please select country/region"
onChange={(value => {this.onChange(value);})} onChange={(value => {this.onChange(value);})}
filterOption={(input, option) => filterOption={(input, option) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase())}
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
}
filterSort={(optionA, optionB) => filterSort={(optionA, optionB) =>
(optionA?.label ?? "").toLowerCase().localeCompare((optionB?.label ?? "").toLowerCase()) (optionA?.label ?? "").toLowerCase().localeCompare((optionB?.label ?? "").toLowerCase())
} }
> >
{ {
Setting.getCountriesData().map((item) => ( Setting.getCountryCodeData().map((item) => (
<Option key={item.code} value={item.code} label={`${item.name} (${item.code})`} > <Option key={item.code} value={item.code} label={`${item.name} (${item.code})`} >
{Setting.countryFlag(item)} {Setting.getCountryImage(item)}
{`${item.name} (${item.code})`} {`${item.name} (${item.code})`}
</Option> </Option>
)) ))

View File

@@ -14,7 +14,7 @@
import React from "react"; import React from "react";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {Checkbox, Form, Modal, Tag, Tooltip, message, theme} from "antd"; import {Checkbox, Form, Modal, Select, Tag, Tooltip, message, theme} from "antd";
import {QuestionCircleTwoTone} from "@ant-design/icons"; import {QuestionCircleTwoTone} from "@ant-design/icons";
import {isMobile as isMobileDevice} from "react-device-detect"; import {isMobile as isMobileDevice} from "react-device-detect";
import "./i18n"; import "./i18n";
@@ -26,6 +26,8 @@ import * as Conf from "./Conf";
import * as phoneNumber from "libphonenumber-js"; import * as phoneNumber from "libphonenumber-js";
import * as path from "path-browserify"; import * as path from "path-browserify";
const {Option} = Select;
export const ServerUrl = ""; export const ServerUrl = "";
// export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static"; // export const StaticBaseUrl = "https://cdn.jsdelivr.net/gh/casbin/static";
@@ -92,7 +94,7 @@ export const OtherProviderInfo = {
url: "https://www.huaweicloud.com/product/msgsms.html", url: "https://www.huaweicloud.com/product/msgsms.html",
}, },
"Twilio SMS": { "Twilio SMS": {
logo: `${StaticBaseUrl}/img/social_twilio.png`, logo: `${StaticBaseUrl}/img/social_twilio.svg`,
url: "https://www.twilio.com/messaging", url: "https://www.twilio.com/messaging",
}, },
"SmsBao SMS": { "SmsBao SMS": {
@@ -206,7 +208,11 @@ export function initCountries() {
return countries; return countries;
} }
export function getCountriesData(countryCodes = phoneNumber.getCountries()) { export function getCountryCode(country) {
return phoneNumber.getCountryCallingCode(country);
}
export function getCountryCodeData(countryCodes = phoneNumber.getCountries()) {
return countryCodes?.map((countryCode) => { return countryCodes?.map((countryCode) => {
if (phoneNumber.isSupportedCountry(countryCode)) { if (phoneNumber.isSupportedCountry(countryCode)) {
const name = initCountries().getName(countryCode, getLanguage()); const name = initCountries().getName(countryCode, getLanguage());
@@ -216,17 +222,28 @@ export function getCountriesData(countryCodes = phoneNumber.getCountries()) {
phone: phoneNumber.getCountryCallingCode(countryCode), phone: phoneNumber.getCountryCallingCode(countryCode),
}; };
} }
}); }).filter(item => item.name !== "")
.sort((a, b) => a.phone - b.phone);
} }
export function countryFlag(country) { export function getCountryCodeOption(country) {
return (
<Option key={country.code} value={country.code} label={`+${country.phone}`} text={`${country.name}, ${country.code}, ${country.phone}`} >
<div style={{display: "flex", justifyContent: "space-between", marginRight: "10px"}}>
<div>
{getCountryImage(country)}
{`${country.name}`}
</div>
{`+${country.phone}`}
</div>
</Option>
);
}
export function getCountryImage(country) {
return <img src={`${StaticBaseUrl}/flag-icons/${country.code}.svg`} alt={country.name} height={20} style={{marginRight: 10}} />; return <img src={`${StaticBaseUrl}/flag-icons/${country.code}.svg`} alt={country.name} height={20} style={{marginRight: 10}} />;
} }
export function getPhoneCodeFromCountryCode(countryCode) {
return phoneNumber.isSupportedCountry(countryCode) ? phoneNumber.getCountryCallingCode(countryCode) : "";
}
export function initServerUrl() { export function initServerUrl() {
// const hostname = window.location.hostname; // const hostname = window.location.hostname;
// if (hostname === "localhost") { // if (hostname === "localhost") {
@@ -332,13 +349,15 @@ export function isValidEmail(email) {
} }
export function isValidPhone(phone, countryCode = "") { export function isValidPhone(phone, countryCode = "") {
if (countryCode !== "") { if (countryCode !== "" && countryCode !== "CN") {
return phoneNumber.isValidPhoneNumber(phone, countryCode); return phoneNumber.isValidPhoneNumber(phone, countryCode);
} }
// // https://learnku.com/articles/31543, `^s*$` filter empty email individually. // https://learnku.com/articles/31543, `^s*$` filter empty email individually.
const phoneCnRegex = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
const phoneRegex = /[0-9]{4,15}$/; const phoneRegex = /[0-9]{4,15}$/;
return phoneRegex.test(phone);
return countryCode === "CN" ? phoneCnRegex.test(phone) : phoneRegex.test(phone);
} }
export function isValidInvoiceTitle(invoiceTitle) { export function isValidInvoiceTitle(invoiceTitle) {

View File

@@ -29,7 +29,7 @@ import SelectRegionBox from "./SelectRegionBox";
import WebAuthnCredentialTable from "./WebauthnCredentialTable"; import WebAuthnCredentialTable from "./WebauthnCredentialTable";
import ManagedAccountTable from "./ManagedAccountTable"; import ManagedAccountTable from "./ManagedAccountTable";
import PropertyTable from "./propertyTable"; import PropertyTable from "./propertyTable";
import PhoneNumberInput from "./common/PhoneNumberInput"; import {PhoneNumberInput} from "./common/PhoneNumberInput";
const {Option} = Select; const {Option} = Select;
@@ -285,25 +285,18 @@ class UserEditPage extends React.Component {
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} : {Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
</Col> </Col>
<Col style={{paddingRight: "20px"}} span={11} > <Col style={{paddingRight: "20px"}} span={11} >
{Setting.isLocalAdminUser(this.props.account) ? <Input
(<Input value={this.state.user.email} value={this.state.user.email}
style={{width: "280Px"}} style={{width: "280Px"}}
disabled={disabled} disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
onChange={e => { onChange={e => {
this.updateUserField("email", e.target.value); this.updateUserField("email", e.target.value);
}} />) : }}
(<Select virtual={false} value={this.state.user.email} />
style={{width: "280Px"}}
options={[Setting.getItem(this.state.user.email, this.state.user.email)]}
disabled={disabled}
onChange={e => {
this.updateUserField("email", e.target.value);
}} />)
}
</Col> </Col>
<Col span={Setting.isMobile() ? 22 : 11} > <Col span={Setting.isMobile() ? 22 : 11} >
{/* backend auto get the current user, so admin can not edit. Just self can reset*/} {/* backend auto get the current user, so admin can not edit. Just self can reset*/}
{this.isSelf() ? <ResetModal application={this.state.application} disabled={disabled} buttonText={i18next.t("user:Reset Email...")} destType={"email"} /> : null} {this.isSelf() ? <ResetModal application={this.state.application} account={this.props.account} disabled={disabled} buttonText={i18next.t("user:Reset Email...")} destType={"email"} /> : null}
</Col> </Col>
</Row> </Row>
); );
@@ -314,34 +307,26 @@ class UserEditPage extends React.Component {
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} : {Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
</Col> </Col>
<Col style={{paddingRight: "20px"}} span={11} > <Col style={{paddingRight: "20px"}} span={11} >
{Setting.isLocalAdminUser(this.props.account) ? <Input.Group compact style={{width: "280Px"}}>
<Input.Group compact style={{width: "280Px"}}> <PhoneNumberInput
<PhoneNumberInput style={{width: "30%"}}
style={{width: "30%"}} // disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
value={this.state.user.countryCode} value={this.state.user.countryCode}
onChange={(value) => { onChange={(value) => {
this.updateUserField("countryCode", value); this.updateUserField("countryCode", value);
}} }}
countryCodes={this.state.application?.organizationObj.countryCodes} countryCodes={this.state.application?.organizationObj.countryCodes}
/> />
<Input value={this.state.user.phone} <Input value={this.state.user.phone}
style={{width: "70%"}} style={{width: "70%"}}
disabled={disabled} disabled={!Setting.isLocalAdminUser(this.props.account) ? true : disabled}
onChange={e => {
this.updateUserField("phone", e.target.value);
}} />
</Input.Group>
:
(<Select virtual={false} value={this.state.user.phone === "" ? null : `+${Setting.getPhoneCodeFromCountryCode(this.state.user.countryCode)} ${this.state.user.phone}`}
options={this.state.user.phone === "" ? null : [Setting.getItem(`+${Setting.getPhoneCodeFromCountryCode(this.state.user.countryCode)} ${this.state.user.phone}`, this.state.user.phone)]}
disabled={disabled}
style={{width: "280px"}}
onChange={e => { onChange={e => {
this.updateUserField("phone", e.target.value); this.updateUserField("phone", e.target.value);
}} />)} }} />
</Input.Group>
</Col> </Col>
<Col span={Setting.isMobile() ? 24 : 11} > <Col span={Setting.isMobile() ? 24 : 11} >
{this.isSelf() ? (<ResetModal application={this.state.application} disabled={disabled} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null} {this.isSelf() ? (<ResetModal application={this.state.application} account={this.props.account} disabled={disabled} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
</Col> </Col>
</Row> </Row>
); );

View File

@@ -36,11 +36,10 @@ export function signup(values) {
}).then(res => res.json()); }).then(res => res.json());
} }
export function getEmailAndPhone(values) { export function getEmailAndPhone(organization, username) {
return fetch(`${authConfig.serverUrl}/api/get-email-and-phone`, { return fetch(`${authConfig.serverUrl}/api/get-email-and-phone?organization=${organization}&username=${username}`, {
method: "POST", method: "GET",
credentials: "include", credentials: "include",
body: JSON.stringify(values),
headers: { headers: {
"Accept-Language": Setting.getAcceptLanguage(), "Accept-Language": Setting.getAcceptLanguage(),
}, },

View File

@@ -24,8 +24,6 @@ import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons"; import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import {withRouter} from "react-router-dom"; import {withRouter} from "react-router-dom";
const {Step} = Steps;
const {Option} = Select; const {Option} = Select;
class ForgetPage extends React.Component { class ForgetPage extends React.Component {
@@ -33,23 +31,21 @@ class ForgetPage extends React.Component {
super(props); super(props);
this.state = { this.state = {
classes: props, classes: props,
account: props.account,
applicationName: props.applicationName ?? props.match.params?.applicationName, applicationName: props.applicationName ?? props.match.params?.applicationName,
application: null, application: null,
msg: null, msg: null,
userId: "", userId: "",
username: "", username: "",
name: "", name: "",
email: "",
isFixed: false,
fixedContent: "",
token: "",
phone: "", phone: "",
emailCode: "", email: "",
phoneCode: "", dest: "",
verifyType: null, // "email" or "phone" isVerifyTypeFixed: false,
verifyType: "", // "email", "phone"
current: 0, current: 0,
}; };
this.form = React.createRef();
} }
componentDidMount() { componentDidMount() {
@@ -88,72 +84,67 @@ class ForgetPage extends React.Component {
switch (name) { switch (name) {
case "step1": case "step1":
const username = forms.step1.getFieldValue("username"); const username = forms.step1.getFieldValue("username");
AuthBackend.getEmailAndPhone({ AuthBackend.getEmailAndPhone(forms.step1.getFieldValue("organization"), username)
application: forms.step1.getFieldValue("application"), .then((res) => {
organization: forms.step1.getFieldValue("organization"), if (res.status === "ok") {
username: username, const phone = res.data.phone;
}).then((res) => { const email = res.data.email;
if (res.status === "ok") {
const phone = res.data.phone; if (phone === "" && email === "") {
const email = res.data.email; Setting.showMessage("error", "no verification method!");
const saveFields = () => { } else {
if (this.state.isFixed) { this.setState({
forms.step2.setFieldsValue({email: this.state.fixedContent}); name: res.data.name,
this.setState({username: this.state.fixedContent}); phone: phone,
email: email,
});
const saveFields = (type, dest, fixed) => {
this.setState({
verifyType: type,
isVerifyTypeFixed: fixed,
dest: dest,
});
};
switch (res.data2) {
case "email":
saveFields("email", email, true);
break;
case "phone":
saveFields("phone", phone, true);
break;
case "username":
phone !== "" ? saveFields("phone", phone, false) : saveFields("email", email, false);
}
this.setState({
current: 1,
});
} }
this.setState({current: 1}); } else {
}; Setting.showMessage("error", res.msg);
this.setState({phone: phone, email: email, username: res.data.name, name: res.data.name});
if (phone !== "" && email === "") {
this.setState({
verifyType: "phone",
});
} else if (phone === "" && email !== "") {
this.setState({
verifyType: "email",
});
} }
});
switch (res.data2) {
case "email":
this.setState({isFixed: true, fixedContent: email, verifyType: "email"}, () => {saveFields();});
break;
case "phone":
this.setState({isFixed: true, fixedContent: phone, verifyType: "phone"}, () => {saveFields();});
break;
default:
saveFields();
break;
}
} else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`));
}
});
break; break;
case "step2": case "step2":
const oAuthParams = Util.getOAuthGetParameters(); const oAuthParams = Util.getOAuthGetParameters();
const login = () => {
AuthBackend.login({ AuthBackend.login({
application: forms.step2.getFieldValue("application"), application: forms.step2.getFieldValue("application"),
organization: forms.step2.getFieldValue("organization"), organization: forms.step2.getFieldValue("organization"),
username: this.state.username, username: forms.step2.getFieldValue("dest"),
name: this.state.name, name: this.state.name,
code: forms.step2.getFieldValue("emailCode"), code: forms.step2.getFieldValue("code"),
type: "login", type: "login",
}, oAuthParams).then(res => { }, oAuthParams).then(res => {
if (res.status === "ok") { if (res.status === "ok") {
this.setState({current: 2, userId: res.data, username: res.data.split("/")[1]}); this.setState({current: 2, userId: res.data});
} else { } else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`)); Setting.showMessage("error", res.msg);
} }
}); });
};
if (this.state.verifyType === "email") {
this.setState({username: this.state.email}, () => {login();});
} else if (this.state.verifyType === "phone") {
this.setState({username: this.state.phone}, () => {login();});
}
break; break;
default: default:
break; break;
@@ -161,13 +152,13 @@ class ForgetPage extends React.Component {
} }
onFinish(values) { onFinish(values) {
values.username = this.state.username; values.username = this.state.name;
values.userOwner = this.getApplicationObj()?.organizationObj.name; values.userOwner = this.getApplicationObj()?.organizationObj.name;
UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => { UserBackend.setPassword(values.userOwner, values.username, "", values?.newPassword).then(res => {
if (res.status === "ok") { if (res.status === "ok") {
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history); Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
} else { } else {
Setting.showMessage("error", i18next.t(`signup:${res.msg}`)); Setting.showMessage("error", res.msg);
} }
}); });
} }
@@ -179,7 +170,7 @@ class ForgetPage extends React.Component {
if (this.state.phone !== "") { if (this.state.phone !== "") {
options.push( options.push(
<Option key={"phone"} value={"phone"}> <Option key={"phone"} value={this.state.phone} >
&nbsp;&nbsp;{this.state.phone} &nbsp;&nbsp;{this.state.phone}
</Option> </Option>
); );
@@ -187,7 +178,7 @@ class ForgetPage extends React.Component {
if (this.state.email !== "") { if (this.state.email !== "") {
options.push( options.push(
<Option key={"email"} value={"email"}> <Option key={"email"} value={this.state.email} >
&nbsp;&nbsp;{this.state.email} &nbsp;&nbsp;{this.state.email}
</Option> </Option>
); );
@@ -202,76 +193,70 @@ class ForgetPage extends React.Component {
this.onFormFinish(name, info, forms); this.onFormFinish(name, info, forms);
}}> }}>
{/* STEP 1: input username -> get email & phone */} {/* STEP 1: input username -> get email & phone */}
<Form {this.state.current === 0 ?
hidden={this.state.current !== 0} <Form
ref={this.form} ref={this.form}
name="step1" name="step1"
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
onFinishFailed={(errorInfo) => console.log(errorInfo)} onFinishFailed={(errorInfo) => console.log(errorInfo)}
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="application"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your application!"
),
},
]}
/>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="organization"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="username"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your username!"
),
whitespace: true,
},
]}
> >
<Input <Form.Item
onChange={(e) => { hidden
this.setState({ name="application"
username: e.target.value, rules={[
}); {
}} required: true,
prefix={<UserOutlined />} message: i18next.t(
placeholder={i18next.t("login:username, Email or phone")} "forget:Please input your application!"
),
},
]}
/> />
</Form.Item> <Form.Item
<br /> hidden
<Form.Item> name="organization"
<Button block type="primary" htmlType="submit"> rules={[
{i18next.t("forget:Next Step")} {
</Button> required: true,
</Form.Item> message: i18next.t(
</Form> "forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="username"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your username!"
),
whitespace: true,
},
]}
>
<Input
prefix={<UserOutlined />}
placeholder={i18next.t("login:username, Email or phone")}
/>
</Form.Item>
<br />
<Form.Item>
<Button block type="primary" htmlType="submit">
{i18next.t("forget:Next Step")}
</Button>
</Form.Item>
</Form> : null}
{/* STEP 2: verify email or phone */} {/* STEP 2: verify email or phone */}
<Form {this.state.current === 1 ? <Form
hidden={this.state.current !== 1}
ref={this.form} ref={this.form}
name="step2" name="step2"
onFinishFailed={(errorInfo) => onFinishFailed={(errorInfo) =>
@@ -281,9 +266,17 @@ class ForgetPage extends React.Component {
errorInfo.outOfDate errorInfo.outOfDate
) )
} }
onValuesChange={(changedValues, allValues) => {
const verifyType = changedValues.dest?.indexOf("@") === -1 ? "phone" : "email";
this.setState({
dest: changedValues.dest,
verifyType: verifyType,
});
}}
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
dest: this.state.dest,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
@@ -301,7 +294,7 @@ class ForgetPage extends React.Component {
]} ]}
/> />
<Form.Item <Form.Item
style={{height: 0, visibility: "hidden"}} hidden
name="organization" name="organization"
rules={[ rules={[
{ {
@@ -313,32 +306,24 @@ class ForgetPage extends React.Component {
]} ]}
/> />
<Form.Item <Form.Item
name="email" // use email instead of email/phone to adapt to RequestForm in account.go name="dest"
validateFirst validateFirst
hasFeedback hasFeedback
> >
{ {
this.state.isFixed ? <Input disabled /> : <Select virtual={false}
<Select virtual={false} disabled={this.state.isVerifyTypeFixed}
key={this.state.verifyType} style={{textAlign: "left"}}
style={{textAlign: "left"}} placeholder={i18next.t("forget:Choose email or phone")}
defaultValue={this.state.verifyType} >
disabled={this.state.username === ""} {
placeholder={i18next.t("forget:Choose email or phone")} this.renderOptions()
onChange={(value) => { }
this.setState({ </Select>
verifyType: value,
});
}}
>
{
this.renderOptions()
}
</Select>
} }
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="emailCode" // use emailCode instead of email/phoneCode to adapt to RequestForm in account.go name="code"
rules={[ rules={[
{ {
required: true, required: true,
@@ -348,21 +333,11 @@ class ForgetPage extends React.Component {
}, },
]} ]}
> >
{this.state.verifyType === "email" ? ( <SendCodeInput disabled={this.state.dest === ""}
<SendCodeInput method={"forget"}
disabled={this.state.username === "" || this.state.verifyType === ""} onButtonClickArgs={[this.state.dest, this.state.verifyType, Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
method={"forget"} application={application}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(this.getApplicationObj()), this.state.name]} />
application={application}
/>
) : (
<SendCodeInput
disabled={this.state.username === "" || this.state.verifyType === ""}
method={"forget"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(this.getApplicationObj()), this.state.name]}
application={application}
/>
)}
</Form.Item> </Form.Item>
<br /> <br />
<Form.Item> <Form.Item>
@@ -374,109 +349,109 @@ class ForgetPage extends React.Component {
{i18next.t("forget:Next Step")} {i18next.t("forget:Next Step")}
</Button> </Button>
</Form.Item> </Form.Item>
</Form> </Form> : null}
{/* STEP 3 */} {/* STEP 3 */}
<Form {this.state.current === 2 ?
hidden={this.state.current !== 2} <Form
ref={this.form} ref={this.form}
name="step3" name="step3"
onFinish={(values) => this.onFinish(values)} onFinish={(values) => this.onFinish(values)}
onFinishFailed={(errorInfo) => onFinishFailed={(errorInfo) =>
this.onFinishFailed( this.onFinishFailed(
errorInfo.values, errorInfo.values,
errorInfo.errorFields, errorInfo.errorFields,
errorInfo.outOfDate errorInfo.outOfDate
) )
} }
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
}} }}
style={{width: "300px"}} style={{width: "300px"}}
size="large" size="large"
>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="application"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your application!"
),
},
]}
/>
<Form.Item
style={{height: 0, visibility: "hidden"}}
name="organization"
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="newPassword"
hidden={this.state.current !== 2}
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your password!"
),
},
]}
hasFeedback
> >
<Input.Password <Form.Item
disabled={this.state.userId === ""} hidden
prefix={<LockOutlined />} name="application"
placeholder={i18next.t("forget:Password")} rules={[
/> {
</Form.Item> required: true,
<Form.Item message: i18next.t(
name="confirm" "forget:Please input your application!"
dependencies={["newPassword"]} ),
hasFeedback
rules={[
{
required: true,
message: i18next.t(
"forget:Please confirm your password!"
),
},
({getFieldValue}) => ({
validator(rule, value) {
if (!value || getFieldValue("newPassword") === value) {
return Promise.resolve();
}
return Promise.reject(
i18next.t(
"forget:Your confirmed password is inconsistent with the password!"
)
);
}, },
}), ]}
]}
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<CheckCircleOutlined />}
placeholder={i18next.t("forget:Confirm")}
/> />
</Form.Item> <Form.Item
<br /> hidden
<Form.Item hidden={this.state.current !== 2}> name="organization"
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}> rules={[
{i18next.t("forget:Change Password")} {
</Button> required: true,
</Form.Item> message: i18next.t(
</Form> "forget:Please input your organization!"
),
},
]}
/>
<Form.Item
name="newPassword"
hidden={this.state.current !== 2}
rules={[
{
required: true,
message: i18next.t(
"forget:Please input your password!"
),
},
]}
hasFeedback
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<LockOutlined />}
placeholder={i18next.t("forget:Password")}
/>
</Form.Item>
<Form.Item
name="confirm"
dependencies={["newPassword"]}
hasFeedback
rules={[
{
required: true,
message: i18next.t(
"forget:Please confirm your password!"
),
},
({getFieldValue}) => ({
validator(rule, value) {
if (!value || getFieldValue("newPassword") === value) {
return Promise.resolve();
}
return Promise.reject(
i18next.t(
"forget:Your confirmed password is inconsistent with the password!"
)
);
},
}),
]}
>
<Input.Password
disabled={this.state.userId === ""}
prefix={<CheckCircleOutlined />}
placeholder={i18next.t("forget:Confirm")}
/>
</Form.Item>
<br />
<Form.Item hidden={this.state.current !== 2}>
<Button block type="primary" htmlType="submit" disabled={this.state.userId === ""}>
{i18next.t("forget:Change Password")}
</Button>
</Form.Item>
</Form> : null}
</Form.Provider> </Form.Provider>
); );
} }
@@ -516,6 +491,20 @@ class ForgetPage extends React.Component {
<Col span={24}> <Col span={24}>
<Steps <Steps
current={this.state.current} current={this.state.current}
items={[
{
title: i18next.t("forget:Account"),
icon: <UserOutlined />,
},
{
title: i18next.t("forget:Account"),
icon: <SolutionOutlined />,
},
{
title: i18next.t("forget:Account"),
icon: <KeyOutlined />,
},
]}
style={{ style={{
width: "90%", width: "90%",
maxWidth: "500px", maxWidth: "500px",
@@ -523,24 +512,12 @@ class ForgetPage extends React.Component {
marginTop: "80px", marginTop: "80px",
}} }}
> >
<Step
title={i18next.t("forget:Account")}
icon={<UserOutlined />}
/>
<Step
title={i18next.t("forget:Verify")}
icon={<SolutionOutlined />}
/>
<Step
title={i18next.t("forget:Reset")}
icon={<KeyOutlined />}
/>
</Steps> </Steps>
</Col> </Col>
</Row> </Row>
</Col> </Col>
<Col span={24} style={{display: "flex", justifyContent: "center"}}> <Col span={24} style={{display: "flex", justifyContent: "center"}}>
<div style={{marginTop: "10px", textAlign: "center"}}> <div style={{marginTop: "40px", textAlign: "center"}}>
{this.renderForm(application)} {this.renderForm(application)}
</div> </div>
</Col> </Col>

View File

@@ -26,7 +26,7 @@ import SelectRegionBox from "../SelectRegionBox";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import SelectLanguageBox from "../SelectLanguageBox"; import SelectLanguageBox from "../SelectLanguageBox";
import {withRouter} from "react-router-dom"; import {withRouter} from "react-router-dom";
import PhoneNumberInput from "../common/PhoneNumberInput"; import {PhoneNumberInput} from "../common/PhoneNumberInput";
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
@@ -82,7 +82,7 @@ class SignupPage extends React.Component {
this.form = React.createRef(); this.form = React.createRef();
} }
UNSAFE_componentWillMount() { componentDidMount() {
let applicationName = this.state.applicationName; let applicationName = this.state.applicationName;
const oAuthParams = Util.getOAuthGetParameters(); const oAuthParams = Util.getOAuthGetParameters();
if (oAuthParams !== null) { if (oAuthParams !== null) {
@@ -390,39 +390,26 @@ class SignupPage extends React.Component {
required: required, required: required,
message: i18next.t("signup:Please select your country code!"), message: i18next.t("signup:Please select your country code!"),
}, },
{
validator: (_, value) => {
if (this.state.phone !== "" && !Setting.isValidPhone(this.state.phone, this.state.countryCode)) {
this.setState({validPhone: false});
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
}
this.setState({validPhone: true});
return Promise.resolve();
},
},
]} ]}
> >
<PhoneNumberInput <PhoneNumberInput
showSearsh={true}
style={{width: "35%"}} style={{width: "35%"}}
value={this.state.countryCode}
onChange={(value) => {this.setState({countryCode: value});}}
countryCodes={this.getApplicationObj().organizationObj.countryCodes} countryCodes={this.getApplicationObj().organizationObj.countryCodes}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="phone" name="phone"
key="phone" key="phone"
dependencies={["countryCode"]}
noStyle noStyle
rules={[ rules={[
{ {
required: required, required: required,
message: i18next.t("signup:Please input your phone number!"), message: i18next.t("signup:Please input your phone number!"),
}, },
{ ({getFieldValue}) => ({
validator: (_, value) => { validator: (_, value) => {
if (this.state.phone !== "" && !Setting.isValidPhone(this.state.phone, this.state.countryCode)) { if (value !== "" && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
this.setState({validPhone: false}); this.setState({validPhone: false});
return Promise.reject(i18next.t("signup:The input is not valid Phone!")); return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
} }
@@ -430,7 +417,7 @@ class SignupPage extends React.Component {
this.setState({validPhone: true}); this.setState({validPhone: true});
return Promise.resolve(); return Promise.resolve();
}, },
}, }),
]} ]}
> >
<Input <Input
@@ -456,6 +443,7 @@ class SignupPage extends React.Component {
method={"signup"} method={"signup"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]} onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
application={application} application={application}
countryCode={this.state.countryCode}
/> />
</Form.Item> </Form.Item>
</React.Fragment> </React.Fragment>
@@ -560,6 +548,7 @@ class SignupPage extends React.Component {
initialValues={{ initialValues={{
application: application.name, application: application.name,
organization: application.organization, organization: application.organization,
countryCode: application.organizationObj.countryCodes?.[0],
}} }}
size="large" size="large"
layout={Setting.isMobile() ? "vertical" : "horizontal"} layout={Setting.isMobile() ? "vertical" : "horizontal"}

View File

@@ -51,7 +51,9 @@ window.fetch = async(url, option = {}) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
originalFetch(url, option).then(res => { originalFetch(url, option).then(res => {
responseFilters.forEach(filter => filter(res.clone())); if (!url.startsWith("/api/get-organizations")) {
responseFilters.forEach(filter => filter(res.clone()));
}
resolve(res); resolve(res);
}); });
}); });

View File

@@ -109,12 +109,13 @@ export function setPassword(userOwner, userName, oldPassword, newPassword) {
}).then(res => res.json()); }).then(res => res.json());
} }
export function sendCode(checkType, checkId, checkKey, method, dest, type, applicationId, checkUser = "") { export function sendCode(checkType, checkId, checkKey, method, countryCode = "", dest, type, applicationId, checkUser = "") {
const formData = new FormData(); const formData = new FormData();
formData.append("checkType", checkType); formData.append("checkType", checkType);
formData.append("checkId", checkId); formData.append("checkId", checkId);
formData.append("checkKey", checkKey); formData.append("checkKey", checkKey);
formData.append("method", method); formData.append("method", method);
formData.append("countryCode", countryCode);
formData.append("dest", dest); formData.append("dest", dest);
formData.append("type", type); formData.append("type", type);
formData.append("applicationId", applicationId); formData.append("applicationId", applicationId);

View File

@@ -61,8 +61,13 @@ class HomePage extends React.Component {
} }
} else { } else {
this.state.applications.forEach(application => { this.state.applications.forEach(application => {
let homepageUrl = application.homepageUrl;
if (homepageUrl === "<custom-url>") {
homepageUrl = this.props.account.homepage;
}
items.push({ items.push({
link: application.homepageUrl, name: application.displayName, organizer: application.description, logo: application.logo, createdTime: "", link: homepageUrl, name: application.displayName, organizer: application.description, logo: application.logo, createdTime: "",
}); });
}); });
} }

View File

@@ -16,12 +16,10 @@ import {Button} from "antd";
import React from "react"; import React from "react";
import i18next from "i18next"; import i18next from "i18next";
import {CaptchaModal} from "./CaptchaModal"; import {CaptchaModal} from "./CaptchaModal";
import * as ProviderBackend from "../backend/ProviderBackend";
import * as UserBackend from "../backend/UserBackend"; import * as UserBackend from "../backend/UserBackend";
export const CaptchaPreview = ({ export const CaptchaPreview = ({
provider, provider,
providerName,
clientSecret, clientSecret,
captchaType, captchaType,
subType, subType,
@@ -41,9 +39,10 @@ export const CaptchaPreview = ({
provider.providerUrl = providerUrl; provider.providerUrl = providerUrl;
if (clientSecret !== "***") { if (clientSecret !== "***") {
provider.clientSecret = clientSecret; provider.clientSecret = clientSecret;
ProviderBackend.updateProvider(owner, providerName, provider).then(() => { // ProviderBackend.updateProvider(owner, providerName, provider).then(() => {
setOpen(true); // setOpen(true);
}); // });
setOpen(true);
} else { } else {
setOpen(true); setOpen(true);
} }

View File

@@ -16,43 +16,29 @@ import {Select} from "antd";
import * as Setting from "../Setting"; import * as Setting from "../Setting";
import React from "react"; import React from "react";
const {Option} = Select; export const PhoneNumberInput = (props) => {
const {onChange, style, disabled, value} = props;
export default function PhoneNumberInput(props) {
const {onChange, style, showSearch} = props;
const value = props.value ?? "CN";
const countryCodes = props.countryCodes ?? []; const countryCodes = props.countryCodes ?? [];
const handleOnChange = (e) => { const handleOnChange = (value) => {
onChange?.(e); onChange?.(value);
}; };
return ( return (
<Select <Select
virtual={false} virtual={false}
showSearch
style={style} style={style}
disabled={disabled}
value={value} value={value}
dropdownMatchSelectWidth={false} dropdownMatchSelectWidth={false}
optionLabelProp={"label"} optionLabelProp={"label"}
showSearch={showSearch}
onChange={handleOnChange} onChange={handleOnChange}
filterOption={(input, option) => filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
}
> >
{ {
Setting.getCountriesData(countryCodes).map((country) => ( Setting.getCountryCodeData(countryCodes).map((country) => Setting.getCountryCodeOption(country))
<Option key={country.code} value={country.code} label={`+${country.phone}`} >
<div style={{display: "flex", justifyContent: "space-between"}}>
<div>
{Setting.countryFlag(country)}
{`${country.name}`}
</div>
{`+${country.phone}`}
</div>
</Option>
))
} }
</Select> </Select>
); );
} };

View File

@@ -22,7 +22,7 @@ import {CaptchaWidget} from "./CaptchaWidget";
const {Search} = Input; const {Search} = Input;
export const SendCodeInput = (props) => { export const SendCodeInput = (props) => {
const {disabled, textBefore, onChange, onButtonClickArgs, application, method} = props; const {disabled, textBefore, onChange, onButtonClickArgs, application, method, countryCode} = props;
const [visible, setVisible] = React.useState(false); const [visible, setVisible] = React.useState(false);
const [key, setKey] = React.useState(""); const [key, setKey] = React.useState("");
const [captchaImg, setCaptchaImg] = React.useState(""); const [captchaImg, setCaptchaImg] = React.useState("");
@@ -53,7 +53,7 @@ export const SendCodeInput = (props) => {
const handleOk = () => { const handleOk = () => {
setVisible(false); setVisible(false);
setButtonLoading(true); setButtonLoading(true);
UserBackend.sendCode(checkType, checkId, key, method, ...onButtonClickArgs).then(res => { UserBackend.sendCode(checkType, checkId, key, method, countryCode, ...onButtonClickArgs).then(res => {
setKey(""); setKey("");
setButtonLoading(false); setButtonLoading(false);
if (res) { if (res) {
@@ -70,7 +70,7 @@ export const SendCodeInput = (props) => {
const loadCaptcha = () => { const loadCaptcha = () => {
UserBackend.getCaptcha(application.owner, application.name, false).then(res => { UserBackend.getCaptcha(application.owner, application.name, false).then(res => {
if (res.type === "none") { if (res.type === "none") {
UserBackend.sendCode("none", "", "", method, ...onButtonClickArgs).then(res => { UserBackend.sendCode("none", "", "", method, countryCode, ...onButtonClickArgs).then(res => {
if (res) { if (res) {
handleCountDown(60); handleCountDown(60);
} }

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Syncers", "Syncers": "Syncers",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Syncers", "Syncers": "Syncers",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sincronizador", "Sync": "Sincronizador",
"Syncers": "Sincronizadores", "Syncers": "Sincronizadores",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Synchronisateurs", "Syncers": "Synchronisateurs",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Syncers", "Syncers": "Syncers",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Syncers", "Syncers": "Syncers",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Синхронизаторы", "Syncers": "Синхронизаторы",

View File

@@ -251,8 +251,8 @@
"Successfully added": "Successfully added", "Successfully added": "Successfully added",
"Successfully deleted": "Successfully deleted", "Successfully deleted": "Successfully deleted",
"Successfully saved": "Successfully saved", "Successfully saved": "Successfully saved",
"Supported country code": "Supported country code", "Supported country codes": "Supported country codes",
"Supported country code - Tooltip": "Supported country code - Tooltip", "Supported country codes - Tooltip": "Supported country codes - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
"Sync": "Sync", "Sync": "Sync",
"Syncers": "Syncers", "Syncers": "Syncers",

View File

@@ -251,8 +251,8 @@
"Successfully added": "添加成功", "Successfully added": "添加成功",
"Successfully deleted": "删除成功", "Successfully deleted": "删除成功",
"Successfully saved": "保存成功", "Successfully saved": "保存成功",
"Supported country code": "支持的国家代码", "Supported country codes": "支持的国家代码",
"Supported country code - Tooltip": "支持发送短信的国家 - Tooltip", "Supported country codes - Tooltip": "支持发送短信的国家 - Tooltip",
"Swagger": "API文档", "Swagger": "API文档",
"Sync": "同步", "Sync": "同步",
"Syncers": "同步器", "Syncers": "同步器",