mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-14 08:03:23 +08:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
d48d515c36 | |||
a5d166c35f | |||
4915963c52 | |||
759a1421e5 | |||
c14bf9fdab | |||
e19f07c521 | |||
39ab71c5db | |||
2c97f8a8b7 | |||
21392dcc14 | |||
953d3d5bc5 | |||
ddee97f544 | |||
c58a6d8725 | |||
a5ff9549c1 | |||
fe57dcbff4 | |||
f8c4ca0f00 | |||
e738c42bd8 | |||
cbc8c58e85 | |||
07c90e048f | |||
a33076ada4 | |||
9cabc4035f |
@ -98,7 +98,7 @@ p, *, *, GET, /api/get-human-check, *, *
|
||||
p, *, *, POST, /api/reset-email-or-phone, *, *
|
||||
p, *, *, POST, /api/upload-resource, *, *
|
||||
p, *, *, GET, /.well-known/openid-configuration, *, *
|
||||
p, *, *, *, /api/certs, *, *
|
||||
p, *, *, *, /.well-known/jwks, *, *
|
||||
p, *, *, GET, /api/get-saml-login, *, *
|
||||
p, *, *, POST, /api/acs, *, *
|
||||
`
|
||||
|
@ -35,6 +35,8 @@ type RequestForm struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Name string `json:"name"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Affiliation string `json:"affiliation"`
|
||||
@ -102,7 +104,7 @@ func (c *ApiController) Signup() {
|
||||
}
|
||||
|
||||
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", form.Organization))
|
||||
msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.Email, form.Phone, form.Affiliation)
|
||||
msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.FirstName, form.LastName, form.Email, form.Phone, form.Affiliation)
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
@ -145,6 +147,8 @@ func (c *ApiController) Signup() {
|
||||
username = id
|
||||
}
|
||||
|
||||
userCount := object.GetUserCount(form.Organization, "", "") + 1
|
||||
|
||||
user := &object.User{
|
||||
Owner: form.Organization,
|
||||
Name: username,
|
||||
@ -167,6 +171,16 @@ func (c *ApiController) Signup() {
|
||||
IsDeleted: false,
|
||||
SignupApplication: application.Name,
|
||||
Properties: map[string]string{},
|
||||
Ranking: userCount + 1,
|
||||
Karma: 0,
|
||||
}
|
||||
|
||||
if application.GetSignupItemRule("Display name") == "First, last" {
|
||||
if form.FirstName != "" || form.LastName != "" {
|
||||
user.DisplayName = fmt.Sprintf("%s %s", form.FirstName, form.LastName)
|
||||
user.FirstName = form.FirstName
|
||||
user.LastName = form.LastName
|
||||
}
|
||||
}
|
||||
|
||||
affected := object.AddUser(user)
|
||||
@ -185,6 +199,11 @@ func (c *ApiController) Signup() {
|
||||
object.DisableVerificationCode(form.Email)
|
||||
object.DisableVerificationCode(checkPhone)
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
go object.AddRecord(record)
|
||||
|
||||
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
|
||||
|
||||
c.ResponseOk(userId)
|
||||
|
@ -221,7 +221,7 @@ func (c *ApiController) Login() {
|
||||
clientSecret = provider.ClientSecret2
|
||||
}
|
||||
|
||||
idProvider := idp.GetIdProvider(provider.Type, provider.SubType, clientId, clientSecret, provider.AppId, form.RedirectUri)
|
||||
idProvider := idp.GetIdProvider(provider.Type, provider.SubType, clientId, clientSecret, provider.AppId, form.RedirectUri, provider.Domain)
|
||||
if idProvider == nil {
|
||||
c.ResponseError(fmt.Sprintf("The provider type: %s is not supported", provider.Type))
|
||||
return
|
||||
|
@ -25,10 +25,10 @@ func (c *RootController) GetOidcDiscovery() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title GetOidcCert
|
||||
// @Title GetJwks
|
||||
// @Tag OIDC API
|
||||
// @router /api/certs [get]
|
||||
func (c *RootController) GetOidcCert() {
|
||||
// @router /.well-known/jwks [get]
|
||||
func (c *RootController) GetJwks() {
|
||||
jwks, err := object.GetJsonWebKeySet()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
116
controllers/product.go
Normal file
116
controllers/product.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2022 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 controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetProducts
|
||||
// @Title GetProducts
|
||||
// @Tag Product API
|
||||
// @Description get products
|
||||
// @Param owner query string true "The owner of products"
|
||||
// @Success 200 {array} object.Product The Response object
|
||||
// @router /get-products [get]
|
||||
func (c *ApiController) GetProducts() {
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetProducts(owner)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetProductCount(owner, field, value)))
|
||||
products := object.GetPaginationProducts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
c.ResponseOk(products, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// @Title GetProduct
|
||||
// @Tag Product API
|
||||
// @Description get product
|
||||
// @Param id query string true "The id of the product"
|
||||
// @Success 200 {object} object.Product The Response object
|
||||
// @router /get-product [get]
|
||||
func (c *ApiController) GetProduct() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetProduct(id)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title UpdateProduct
|
||||
// @Tag Product API
|
||||
// @Description update product
|
||||
// @Param id query string true "The id of the product"
|
||||
// @Param body body object.Product true "The details of the product"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-product [post]
|
||||
func (c *ApiController) UpdateProduct() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var product object.Product
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateProduct(id, &product))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title AddProduct
|
||||
// @Tag Product API
|
||||
// @Description add product
|
||||
// @Param body body object.Product true "The details of the product"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-product [post]
|
||||
func (c *ApiController) AddProduct() {
|
||||
var product object.Product
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddProduct(&product))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title DeleteProduct
|
||||
// @Tag Product API
|
||||
// @Description delete product
|
||||
// @Param body body object.Product true "The details of the product"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-product [post]
|
||||
func (c *ApiController) DeleteProduct() {
|
||||
var product object.Product
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))
|
||||
c.ServeJSON()
|
||||
}
|
@ -171,12 +171,16 @@ func (c *ApiController) GetOAuthToken() {
|
||||
clientSecret := c.Input().Get("client_secret")
|
||||
code := c.Input().Get("code")
|
||||
verifier := c.Input().Get("code_verifier")
|
||||
scope := c.Input().Get("scope")
|
||||
username := c.Input().Get("username")
|
||||
password := c.Input().Get("password")
|
||||
|
||||
if clientId == "" && clientSecret == "" {
|
||||
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
|
||||
}
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier)
|
||||
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ services:
|
||||
RUNNING_IN_DOCKER: "true"
|
||||
volumes:
|
||||
- ./conf:/conf/
|
||||
restart: always
|
||||
db:
|
||||
restart: always
|
||||
image: mysql:8.0.25
|
||||
@ -23,4 +22,4 @@ services:
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: 123456
|
||||
volumes:
|
||||
- /usr/local/docker/mysql:/var/lib/mysql
|
||||
- /usr/local/docker/mysql:/var/lib/mysql
|
||||
|
3
go.mod
3
go.mod
@ -17,6 +17,7 @@ require (
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/jinzhu/configor v1.2.1 // indirect
|
||||
github.com/lestrrat-go/jwx v0.9.0
|
||||
github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76
|
||||
@ -25,7 +26,7 @@ require (
|
||||
github.com/russellhaering/goxmldsig v1.1.1
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/thanhpk/randstr v1.0.4
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
|
102
go.sum
102
go.sum
@ -20,23 +20,18 @@ cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNF
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
@ -44,40 +39,30 @@ github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzU
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
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/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U=
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
|
||||
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/aliyun-oss-go-sdk v2.1.6+incompatible h1:Ft+KeWIJxFP76LqgJbvtOA1qBIoC8vGkTV3QeCOeJC4=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
|
||||
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
|
||||
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go v1.37.30 h1:fZeVg3QuTkWE/dEvPQbK6AL32+3G9ofJfGFSPS1XLH0=
|
||||
github.com/aws/aws-sdk-go v1.37.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd h1:jZtX5jh5IOMu0fpOTC3ayh6QGSPJ/KWOv1lgPvbRw1M=
|
||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542 h1:nYXb+3jF6Oq/j8R/y90XrKpreCxIalBWfeyeKymgOPk=
|
||||
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/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
@ -85,7 +70,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||
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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
|
||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||
@ -97,94 +81,64 @@ github.com/casbin/xorm-adapter/v2 v2.5.1 h1:BkpIxRHKa0s3bSMx173PpuU7oTs+Zw7XmD0B
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1/go.mod h1:AeH4dBKHC9/zYxzdPVHhPDzF8LYLqjDdb767CWJoV54=
|
||||
github.com/casdoor/go-sms-sender v0.0.5 h1:9qhlMM+UoSOvvY7puUULqSHBBA7fbe02Px/tzchQboo=
|
||||
github.com/casdoor/go-sms-sender v0.0.5/go.mod h1:TMM/BsZQAa+7JVDXl2KqgxnzZgCjmHEX5MBN662mM5M=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d h1:OMrhQqj1QCyDT2sxHCDjE+k8aMdn2ngTCGG7g4wrdLo=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808 h1:8s2l8TVUwMXl6tZMe3+hPCRJ25nQXiA3d1x622JtOqc=
|
||||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a h1:Y5XsLCEhtEI8qbD9RP3Qlv5FXdTDHxZM9UPUnMRgBp8=
|
||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elastic/go-elasticsearch/v6 v6.8.5 h1:U2HtkBseC1FNBmDr0TR2tKltL6FxoY+niDAlj5M8TK8=
|
||||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c h1:iRTj5SRYwbvsygdwVp+y9kZT145Y1s6xOPpeOEIeGc4=
|
||||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
|
||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
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-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
|
||||
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.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d h1:lBXNCxVENCipq4D1Is42JVOP4eQjlB8TQ6H69Yx5J9Q=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@ -215,7 +169,6 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
|
||||
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@ -226,11 +179,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
@ -239,15 +189,12 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7 h1:k+KkMRk8mGOu1xG38StS7dQ+Z6oW1i9n3dgrAVU9Q/E=
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||
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.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.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.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
@ -257,9 +204,7 @@ github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE=
|
||||
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@ -267,9 +212,7 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk=
|
||||
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
|
||||
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
|
||||
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
|
||||
@ -286,29 +229,22 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
||||
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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6 h1:wxyqOzKxsRJ6vVRL9sXQ64Z45wmBuQ+OTH9sLsC5rKc=
|
||||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
|
||||
github.com/lestrrat-go/jwx v0.9.0 h1:Fnd0EWzTm0kFrBPzE/PEPp9nzllES5buMkksPMjEKpM=
|
||||
github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk=
|
||||
@ -336,9 +272,7 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=
|
||||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@ -348,11 +282,8 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233 h1:jmJndGFBPjNWW+MAYarU/Nl8QrQVzbw4B/AYE0LzETo=
|
||||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
|
||||
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.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -395,31 +326,26 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0 h1:QIF48X1cihydXibm+4wfAc0r/qyPyuFiPFRNphdMpEE=
|
||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400 h1:091wFNQB3PXcL5+me0joH7EiyqQaI0wGMpEjVCkK04U=
|
||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs=
|
||||
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.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec h1:q6XVwXmKvCRHRqesF3cSv6lNqqHi0QWOvgDlSohg8UA=
|
||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
@ -430,26 +356,20 @@ github.com/tencentcloud/tencentcloud-sdk-go v1.0.154 h1:THBgwGwUQtsw6L53cSSA2wwL
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
|
||||
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
|
||||
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
||||
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83 h1:9AUN7+NK4IV+A11igqjQM5i8obiOAQo4SXgjaxe+orI=
|
||||
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/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
|
||||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b h1:0Ve0/CCjiAiyKddUMUn3RwIGlq2iTW4GuVzyoKBYO/8=
|
||||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973 h1:iCnkJ/qjKZGdZnlcj1N55AxPDan814kpc3s1cDpQKd8=
|
||||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
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.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
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=
|
||||
@ -470,10 +390,8 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -484,17 +402,14 @@ 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-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-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
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-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -546,7 +461,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -586,7 +500,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -642,7 +555,6 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f h1:18s2P7JILnVhIF2+ZtGJQ9czV5bvTsb13/UGtNPDbjA=
|
||||
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -665,7 +577,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.32.0 h1:Le77IccnTqEa8ryp9wIpX5W3zYm7Gf9LhOp9PHcwFts=
|
||||
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@ -705,7 +616,6 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200929141702-51c3e5b607fe h1:6SgESkjJknFUnsfQ2yxQbmTAi37BxhwS/riq+VdLo9c=
|
||||
google.golang.org/genproto v0.0.0-20200929141702-51c3e5b607fe/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
@ -720,7 +630,6 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@ -733,7 +642,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
@ -743,7 +651,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
||||
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/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
@ -752,7 +659,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
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=
|
||||
@ -774,13 +680,9 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
|
136
idp/adfs.go
Normal file
136
idp/adfs.go
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright 2022 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 idp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/lestrrat-go/jwx/jwa"
|
||||
"github.com/lestrrat-go/jwx/jwk"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type AdfsIdProvider struct {
|
||||
Client *http.Client
|
||||
Config *oauth2.Config
|
||||
Host string
|
||||
}
|
||||
|
||||
func NewAdfsIdProvider(clientId string, clientSecret string, redirectUrl string, hostUrl string) *AdfsIdProvider {
|
||||
idp := &AdfsIdProvider{}
|
||||
|
||||
config := idp.getConfig(hostUrl)
|
||||
config.ClientID = clientId
|
||||
config.ClientSecret = clientSecret
|
||||
config.RedirectURL = redirectUrl
|
||||
idp.Config = config
|
||||
idp.Host = hostUrl
|
||||
return idp
|
||||
}
|
||||
|
||||
func (idp *AdfsIdProvider) SetHttpClient(client *http.Client) {
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
idp.Client = client
|
||||
idp.Client.Transport = tr
|
||||
}
|
||||
|
||||
func (idp *AdfsIdProvider) getConfig(hostUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s/adfs/oauth2/authorize", hostUrl),
|
||||
TokenURL: fmt.Sprintf("%s/adfs/oauth2/token", hostUrl),
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
type AdfsToken struct {
|
||||
IdToken string `json:"id_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
ErrMsg string `json:"error_description"`
|
||||
}
|
||||
|
||||
// get more detail via: https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-openid-connect-oauth-flows-scenarios#request-an-access-token
|
||||
func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
payload := url.Values{}
|
||||
payload.Set("code", code)
|
||||
payload.Set("grant_type", "authorization_code")
|
||||
payload.Set("client_id", idp.Config.ClientID)
|
||||
payload.Set("redirect_uri", idp.Config.RedirectURL)
|
||||
resp, err := idp.Client.PostForm(idp.Config.Endpoint.TokenURL, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pToken := &AdfsToken{}
|
||||
err = json.Unmarshal(data, pToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to unmarshal token response: %s", err.Error())
|
||||
}
|
||||
if pToken.ErrMsg != "" {
|
||||
return nil, fmt.Errorf("pToken.Errmsg = %s", pToken.ErrMsg)
|
||||
}
|
||||
|
||||
token := &oauth2.Token{
|
||||
AccessToken: pToken.IdToken,
|
||||
Expiry: time.Unix(time.Now().Unix()+int64(pToken.ExpiresIn), 0),
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// Since the userinfo endpoint of ADFS only returns sub,
|
||||
// the id_token is used to resolve the userinfo
|
||||
func (idp *AdfsIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
resp, err := idp.Client.Get(fmt.Sprintf("%s/adfs/discovery/keys", idp.Host))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyset, err := jwk.Parse(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenSrc := []byte(token.AccessToken)
|
||||
publicKey, _ := keyset.Keys[0].Materialize()
|
||||
id_token, _ := jwt.Parse(bytes.NewReader(tokenSrc), jwt.WithVerify(jwa.RS256, publicKey))
|
||||
sid, _ := id_token.Get("sid")
|
||||
upn, _ := id_token.Get("upn")
|
||||
name, _ := id_token.Get("unique_name")
|
||||
userinfo := &UserInfo{
|
||||
Id: sid.(string),
|
||||
Username: name.(string),
|
||||
DisplayName: name.(string),
|
||||
Email: upn.(string),
|
||||
}
|
||||
return userinfo, nil
|
||||
}
|
@ -122,9 +122,9 @@ func (idp *FacebookIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
//}
|
||||
|
||||
type FacebookUserInfo struct {
|
||||
Id string `json:"id"` // The app user's App-Scoped User ID. This ID is unique to the app and cannot be used by other apps.
|
||||
Name string `json:"name"` // The person's full name.
|
||||
NameFormat string `json:"name_format"` // The person's name formatted to correctly handle Chinese, Japanese, or Korean ordering.
|
||||
Id string `json:"id"` // The app user's App-Scoped User ID. This ID is unique to the app and cannot be used by other apps.
|
||||
Name string `json:"name"` // The person's full name.
|
||||
NameFormat string `json:"name_format"` // The person's name formatted to correctly handle Chinese, Japanese, or Korean ordering.
|
||||
Picture struct { // The person's profile picture.
|
||||
Data struct { // This struct is different as https://developers.facebook.com/docs/graph-api/reference/user/picture/
|
||||
Height int `json:"height"`
|
||||
@ -164,6 +164,7 @@ func (idp *FacebookIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
|
||||
userInfo := UserInfo{
|
||||
Id: facebookUserInfo.Id,
|
||||
Username: facebookUserInfo.Name,
|
||||
DisplayName: facebookUserInfo.Name,
|
||||
Email: facebookUserInfo.Email,
|
||||
AvatarUrl: facebookUserInfo.Picture.Data.Url,
|
||||
|
@ -35,7 +35,7 @@ type IdProvider interface {
|
||||
GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
}
|
||||
|
||||
func GetIdProvider(typ string, subType string, clientId string, clientSecret string, appId string, redirectUrl string) IdProvider {
|
||||
func GetIdProvider(typ string, subType string, clientId string, clientSecret string, appId string, redirectUrl string, hostUrl string) IdProvider {
|
||||
if typ == "GitHub" {
|
||||
return NewGithubIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if typ == "Google" {
|
||||
@ -66,6 +66,8 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
|
||||
return NewLarkIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if typ == "GitLab" {
|
||||
return NewGitlabIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if typ == "Adfs" {
|
||||
return NewAdfsIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
|
||||
} else if typ == "Baidu" {
|
||||
return NewBaiduIdProvider(clientId, clientSecret, redirectUrl)
|
||||
} else if typ == "Infoflow" {
|
||||
|
@ -17,7 +17,6 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"xorm.io/core"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
@ -25,6 +24,7 @@ import (
|
||||
//_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||
//_ "github.com/lib/pq" // db = postgres
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@ -183,6 +183,11 @@ func (a *Adapter) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Product))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Payment))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -38,6 +38,7 @@ type Application struct {
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
||||
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
|
||||
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
|
||||
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
|
||||
|
||||
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
||||
|
@ -33,7 +33,7 @@ func init() {
|
||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||
}
|
||||
|
||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, email string, phone string, affiliation string) string {
|
||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, affiliation string) string {
|
||||
if organization == nil {
|
||||
return "organization does not exist"
|
||||
}
|
||||
@ -85,11 +85,19 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
||||
}
|
||||
|
||||
if application.IsSignupItemVisible("Display name") {
|
||||
if displayName == "" {
|
||||
return "displayName cannot be blank"
|
||||
} else if application.GetSignupItemRule("Display name") == "Personal" {
|
||||
if !isValidPersonalName(displayName) {
|
||||
return "displayName is not valid personal name"
|
||||
if application.GetSignupItemRule("Display name") == "First, last" && (firstName != "" || lastName != "") {
|
||||
if firstName == "" {
|
||||
return "firstName cannot be blank"
|
||||
} else if lastName == "" {
|
||||
return "lastName cannot be blank"
|
||||
}
|
||||
} else {
|
||||
if displayName == "" {
|
||||
return "displayName cannot be blank"
|
||||
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
||||
if !isValidRealName(displayName) {
|
||||
return "displayName is not valid real name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,16 @@ package object
|
||||
|
||||
import "regexp"
|
||||
|
||||
var rePersonalName *regexp.Regexp
|
||||
var reRealName *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
rePersonalName, err = regexp.Compile("^[\u4E00-\u9FA5]{2,3}(?:·[\u4E00-\u9FA5]{2,3})*$")
|
||||
reRealName, err = regexp.Compile("^[\u4E00-\u9FA5]{2,3}(?:·[\u4E00-\u9FA5]{2,3})*$")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidPersonalName(s string) bool {
|
||||
return rePersonalName.MatchString(s)
|
||||
func isValidRealName(s string) bool {
|
||||
return reRealName.MatchString(s)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
||||
AuthorizationEndpoint: fmt.Sprintf("%s/login/oauth/authorize", originFrontend),
|
||||
TokenEndpoint: fmt.Sprintf("%s/api/login/oauth/access_token", originBackend),
|
||||
UserinfoEndpoint: fmt.Sprintf("%s/api/userinfo", originBackend),
|
||||
JwksUri: fmt.Sprintf("%s/api/certs", originBackend),
|
||||
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
|
||||
ResponseTypesSupported: []string{"id_token"},
|
||||
ResponseModesSupported: []string{"login", "code", "link"},
|
||||
GrantTypesSupported: []string{"password", "authorization_code"},
|
||||
@ -89,21 +89,22 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
||||
}
|
||||
|
||||
func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
|
||||
cert := GetDefaultCert()
|
||||
|
||||
certs := GetCerts("admin")
|
||||
jwks := jose.JSONWebKeySet{}
|
||||
//follows the protocol rfc 7517(draft)
|
||||
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
||||
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
||||
certPemBlock := []byte(cert.PublicKey)
|
||||
certDerBlock, _ := pem.Decode(certPemBlock)
|
||||
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)
|
||||
for _, cert := range certs {
|
||||
certPemBlock := []byte(cert.PublicKey)
|
||||
certDerBlock, _ := pem.Decode(certPemBlock)
|
||||
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)
|
||||
|
||||
var jwk jose.JSONWebKey
|
||||
jwk.Key = x509Cert.PublicKey
|
||||
jwk.Certificates = []*x509.Certificate{x509Cert}
|
||||
jwk.KeyID = cert.Name
|
||||
var jwk jose.JSONWebKey
|
||||
jwk.Key = x509Cert.PublicKey
|
||||
jwk.Certificates = []*x509.Certificate{x509Cert}
|
||||
jwk.KeyID = cert.Name
|
||||
jwks.Keys = append(jwks.Keys, jwk)
|
||||
}
|
||||
|
||||
var jwks jose.JSONWebKeySet
|
||||
jwks.Keys = []jose.JSONWebKey{jwk}
|
||||
return jwks, nil
|
||||
}
|
||||
|
130
object/product.go
Normal file
130
object/product.go
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2022 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 object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
|
||||
Image string `xorm:"varchar(100)" json:"image"`
|
||||
Detail string `xorm:"varchar(100)" json:"detail"`
|
||||
Tag string `xorm:"varchar(100)" json:"tag"`
|
||||
Currency string `xorm:"varchar(100)" json:"currency"`
|
||||
Price int `json:"price"`
|
||||
Quantity int `json:"quantity"`
|
||||
Sold int `json:"sold"`
|
||||
Providers []string `xorm:"varchar(100)" json:"providers"`
|
||||
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
}
|
||||
|
||||
func GetProductCount(owner, field, value string) int {
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
count, err := session.Count(&Product{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return int(count)
|
||||
}
|
||||
|
||||
func GetProducts(owner string) []*Product {
|
||||
products := []*Product{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&products, &Product{Owner: owner})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
func GetPaginationProducts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Product {
|
||||
products := []*Product{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&products)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
func getProduct(owner string, name string) *Product {
|
||||
if owner == "" || name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
product := Product{Owner: owner, Name: name}
|
||||
existed, err := adapter.Engine.Get(&product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &product
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetProduct(id string) *Product {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getProduct(owner, name)
|
||||
}
|
||||
|
||||
func UpdateProduct(id string, product *Product) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getProduct(owner, name) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func AddProduct(product *Product) bool {
|
||||
affected, err := adapter.Engine.Insert(product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func DeleteProduct(product *Product) bool {
|
||||
affected, err := adapter.Engine.ID(core.PK{product.Owner, product.Name}).Delete(&Product{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func (product *Product) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", product.Owner, product.Name)
|
||||
}
|
188
object/token.go
188
object/token.go
@ -17,6 +17,7 @@ package object
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@ -261,7 +262,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
|
||||
}
|
||||
}
|
||||
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string) *TokenWrapper {
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string) *TokenWrapper {
|
||||
application := GetApplicationByClientId(clientId)
|
||||
if application == nil {
|
||||
return &TokenWrapper{
|
||||
@ -272,75 +273,30 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
|
||||
}
|
||||
}
|
||||
|
||||
if grantType != "authorization_code" {
|
||||
//Check if grantType is allowed in the current application
|
||||
if !isGrantTypeValid(grantType, application.GrantTypes) {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: grant_type should be \"authorization_code\"",
|
||||
AccessToken: fmt.Sprintf("error: grant_type: %s is not supported in this application", grantType),
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if code == "" {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: authorization code should not be empty",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
var token *Token
|
||||
var err error
|
||||
switch grantType {
|
||||
case "authorization_code": // Authorization Code Grant
|
||||
token, err = GetAuthorizationCodeToken(application, clientSecret, code, verifier)
|
||||
case "password": // Resource Owner Password Credentials Grant
|
||||
token, err = GetPasswordToken(application, username, password, scope, host)
|
||||
case "client_credentials": // Client Credentials Grant
|
||||
token, err = GetClientCredentialsToken(application, clientSecret, scope, host)
|
||||
}
|
||||
|
||||
token := getTokenByCode(code)
|
||||
if token == nil {
|
||||
if err != nil {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: invalid authorization code",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if application.Name != token.Application {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: the token is for wrong application (client_id)",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if application.ClientSecret != clientSecret {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: invalid client_secret",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if token.CodeChallenge != "" && pkceChallenge(verifier) != token.CodeChallenge {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: incorrect code_verifier",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if token.CodeIsUsed {
|
||||
// anti replay attacks
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: authorization code has been used",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
|
||||
if time.Now().Unix() > token.CodeExpireIn {
|
||||
// code must be used within 5 minutes
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: authorization code has expired",
|
||||
AccessToken: err.Error(),
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
@ -459,3 +415,115 @@ func pkceChallenge(verifier string) string {
|
||||
challenge := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(sum[:])
|
||||
return challenge
|
||||
}
|
||||
|
||||
// Check if grantType is allowed in the current application
|
||||
// authorization_code is allowed by default
|
||||
func isGrantTypeValid(method string, grantTypes []string) bool {
|
||||
if method == "authorization_code" {
|
||||
return true
|
||||
}
|
||||
for _, m := range grantTypes {
|
||||
if m == method {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Authorization code flow
|
||||
func GetAuthorizationCodeToken(application *Application, clientSecret string, code string, verifier string) (*Token, error) {
|
||||
if code == "" {
|
||||
return nil, errors.New("error: authorization code should not be empty")
|
||||
}
|
||||
|
||||
token := getTokenByCode(code)
|
||||
if token == nil {
|
||||
return nil, errors.New("error: invalid authorization code")
|
||||
}
|
||||
if token.CodeIsUsed {
|
||||
// anti replay attacks
|
||||
return nil, errors.New("error: authorization code has been used")
|
||||
}
|
||||
if application.ClientSecret != clientSecret {
|
||||
return nil, errors.New("error: invalid client_secret")
|
||||
}
|
||||
|
||||
if application.Name != token.Application {
|
||||
return nil, errors.New("error: the token is for wrong application (client_id)")
|
||||
}
|
||||
|
||||
if token.CodeChallenge != "" && pkceChallenge(verifier) != token.CodeChallenge {
|
||||
return nil, errors.New("error: incorrect code_verifier")
|
||||
}
|
||||
|
||||
if time.Now().Unix() > token.CodeExpireIn {
|
||||
// code must be used within 5 minutes
|
||||
return nil, errors.New("error: authorization code has expired")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// Resource Owner Password Credentials flow
|
||||
func GetPasswordToken(application *Application, username string, password string, scope string, host string) (*Token, error) {
|
||||
user := getUser(application.Organization, username)
|
||||
if user == nil {
|
||||
return nil, errors.New("error: the user does not exist")
|
||||
}
|
||||
if user.Password != password {
|
||||
return nil, errors.New("error: invalid username or password")
|
||||
}
|
||||
if user.IsForbidden {
|
||||
return nil, errors.New("error: the user is forbidden to sign in, please contact the administrator")
|
||||
}
|
||||
accessToken, refreshToken, err := generateJwtToken(application, user, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
AddToken(token)
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// Client Credentials flow
|
||||
func GetClientCredentialsToken(application *Application, clientSecret string, scope string, host string) (*Token, error) {
|
||||
if application.ClientSecret != clientSecret {
|
||||
return nil, errors.New("error: invalid client_secret")
|
||||
}
|
||||
nullUser := &User{
|
||||
Name: fmt.Sprintf("app/%s", application.Name),
|
||||
}
|
||||
accessToken, _, err := generateJwtToken(application, nullUser, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: application.Organization,
|
||||
User: nullUser.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
AddToken(token)
|
||||
return token, nil
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ type User struct {
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
FirstName string `xorm:"varchar(100)" json:"firstName"`
|
||||
LastName string `xorm:"varchar(100)" json:"lastName"`
|
||||
Avatar string `xorm:"varchar(500)" json:"avatar"`
|
||||
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
|
||||
Email string `xorm:"varchar(100) index" json:"email"`
|
||||
@ -53,6 +55,7 @@ type User struct {
|
||||
Birthday string `xorm:"varchar(100)" json:"birthday"`
|
||||
Education string `xorm:"varchar(100)" json:"education"`
|
||||
Score int `json:"score"`
|
||||
Karma int `json:"karma"`
|
||||
Ranking int `json:"ranking"`
|
||||
IsDefaultAvatar bool `json:"isDefaultAvatar"`
|
||||
IsOnline bool `json:"isOnline"`
|
||||
@ -80,6 +83,7 @@ type User struct {
|
||||
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
|
||||
Lark string `xorm:"lark varchar(100)" json:"lark"`
|
||||
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
||||
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
|
||||
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
||||
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
|
||||
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
||||
|
@ -62,7 +62,7 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
// "/page?username=abc&password=123"
|
||||
userId = ctx.Input.Query("username")
|
||||
password := ctx.Input.Query("password")
|
||||
if userId != "" && password != "" {
|
||||
if userId != "" && password != "" && ctx.Input.Query("grant_type") == "" {
|
||||
owner, name := util.GetOwnerAndNameFromId(userId)
|
||||
_, msg := object.CheckUserPassword(owner, name, password)
|
||||
if msg != "" {
|
||||
|
@ -54,7 +54,7 @@ func getUserByClientIdSecret(ctx *context.Context) string {
|
||||
}
|
||||
|
||||
func RecordMessage(ctx *context.Context) {
|
||||
if ctx.Request.URL.Path == "/api/login" {
|
||||
if ctx.Request.URL.Path == "/api/login" || ctx.Request.URL.Path == "/api/signup" {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,12 @@ func initAPI() {
|
||||
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
||||
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
||||
|
||||
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
|
||||
beego.Router("/api/get-product", &controllers.ApiController{}, "GET:GetProduct")
|
||||
beego.Router("/api/update-product", &controllers.ApiController{}, "POST:UpdateProduct")
|
||||
beego.Router("/api/add-product", &controllers.ApiController{}, "POST:AddProduct")
|
||||
beego.Router("/api/delete-product", &controllers.ApiController{}, "POST:DeleteProduct")
|
||||
|
||||
beego.Router("/api/get-payments", &controllers.ApiController{}, "GET:GetPayments")
|
||||
beego.Router("/api/get-payment", &controllers.ApiController{}, "GET:GetPayment")
|
||||
beego.Router("/api/update-payment", &controllers.ApiController{}, "POST:UpdatePayment")
|
||||
@ -159,5 +165,5 @@ func initAPI() {
|
||||
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
|
||||
|
||||
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
|
||||
beego.Router("/api/certs", &controllers.RootController{}, "*:GetOidcCert")
|
||||
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
|
||||
}
|
||||
|
@ -10,6 +10,14 @@
|
||||
},
|
||||
"basePath": "/",
|
||||
"paths": {
|
||||
"/.well-known/jwks": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"OIDC API"
|
||||
],
|
||||
"operationId": "RootController.GetJwks"
|
||||
}
|
||||
},
|
||||
"/.well-known/openid-configuration": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@ -442,14 +450,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/certs": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"OIDC API"
|
||||
],
|
||||
"operationId": "RootController.GetOidcCert"
|
||||
}
|
||||
},
|
||||
"/api/check-ldap-users-exist": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@ -2476,11 +2476,11 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"1867.0xc0003b2ea0.false": {
|
||||
"1867.0xc00029b560.false": {
|
||||
"title": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"1901.0xc0003b2ed0.false": {
|
||||
"1901.0xc00029b590.false": {
|
||||
"title": "false",
|
||||
"type": "object"
|
||||
},
|
||||
@ -2497,10 +2497,10 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/1867.0xc0003b2ea0.false"
|
||||
"$ref": "#/definitions/1867.0xc00029b560.false"
|
||||
},
|
||||
"data2": {
|
||||
"$ref": "#/definitions/1901.0xc0003b2ed0.false"
|
||||
"$ref": "#/definitions/1901.0xc00029b590.false"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string"
|
||||
@ -2521,10 +2521,10 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/1867.0xc0003b2ea0.false"
|
||||
"$ref": "#/definitions/1867.0xc00029b560.false"
|
||||
},
|
||||
"data2": {
|
||||
"$ref": "#/definitions/1901.0xc0003b2ed0.false"
|
||||
"$ref": "#/definitions/1901.0xc00029b590.false"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string"
|
||||
@ -3213,6 +3213,9 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"adfs": {
|
||||
"type": "string"
|
||||
},
|
||||
"affiliation": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -7,6 +7,11 @@ info:
|
||||
email: admin@casbin.org
|
||||
basePath: /
|
||||
paths:
|
||||
/.well-known/jwks:
|
||||
get:
|
||||
tags:
|
||||
- OIDC API
|
||||
operationId: RootController.GetJwks
|
||||
/.well-known/openid-configuration:
|
||||
get:
|
||||
tags:
|
||||
@ -286,11 +291,6 @@ paths:
|
||||
description: object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
/api/certs:
|
||||
get:
|
||||
tags:
|
||||
- OIDC API
|
||||
operationId: RootController.GetOidcCert
|
||||
/api/check-ldap-users-exist:
|
||||
post:
|
||||
tags:
|
||||
@ -1620,10 +1620,10 @@ paths:
|
||||
schema:
|
||||
$ref: '#/definitions/object.Userinfo'
|
||||
definitions:
|
||||
1867.0xc0003b2ea0.false:
|
||||
1867.0xc00029b560.false:
|
||||
title: "false"
|
||||
type: object
|
||||
1901.0xc0003b2ed0.false:
|
||||
1901.0xc00029b590.false:
|
||||
title: "false"
|
||||
type: object
|
||||
RequestForm:
|
||||
@ -1637,9 +1637,9 @@ definitions:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/definitions/1867.0xc0003b2ea0.false'
|
||||
$ref: '#/definitions/1867.0xc00029b560.false'
|
||||
data2:
|
||||
$ref: '#/definitions/1901.0xc0003b2ed0.false'
|
||||
$ref: '#/definitions/1901.0xc00029b590.false'
|
||||
msg:
|
||||
type: string
|
||||
name:
|
||||
@ -1653,9 +1653,9 @@ definitions:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/definitions/1867.0xc0003b2ea0.false'
|
||||
$ref: '#/definitions/1867.0xc00029b560.false'
|
||||
data2:
|
||||
$ref: '#/definitions/1901.0xc0003b2ed0.false'
|
||||
$ref: '#/definitions/1901.0xc00029b590.false'
|
||||
msg:
|
||||
type: string
|
||||
name:
|
||||
@ -2118,6 +2118,8 @@ definitions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
adfs:
|
||||
type: string
|
||||
affiliation:
|
||||
type: string
|
||||
apple:
|
||||
|
@ -43,6 +43,9 @@ import SyncerListPage from "./SyncerListPage";
|
||||
import SyncerEditPage from "./SyncerEditPage";
|
||||
import CertListPage from "./CertListPage";
|
||||
import CertEditPage from "./CertEditPage";
|
||||
import ProductListPage from "./ProductListPage";
|
||||
import ProductEditPage from "./ProductEditPage";
|
||||
import ProductBuyPage from "./ProductBuyPage";
|
||||
import PaymentListPage from "./PaymentListPage";
|
||||
import PaymentEditPage from "./PaymentEditPage";
|
||||
import AccountPage from "./account/AccountPage";
|
||||
@ -128,6 +131,8 @@ class App extends Component {
|
||||
this.setState({ selectedMenuKey: '/syncers' });
|
||||
} else if (uri.includes('/certs')) {
|
||||
this.setState({ selectedMenuKey: '/certs' });
|
||||
} else if (uri.includes('/products')) {
|
||||
this.setState({ selectedMenuKey: '/products' });
|
||||
} else if (uri.includes('/payments')) {
|
||||
this.setState({ selectedMenuKey: '/payments' });
|
||||
} else if (uri.includes('/signup')) {
|
||||
@ -141,16 +146,14 @@ class App extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
getAccessTokenParam() {
|
||||
getAccessTokenParam(params) {
|
||||
// "/page?access_token=123"
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
const accessToken = params.get("access_token");
|
||||
return accessToken === null ? "" : `?accessToken=${accessToken}`;
|
||||
}
|
||||
|
||||
getCredentialParams() {
|
||||
getCredentialParams(params) {
|
||||
// "/page?username=abc&password=123"
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
if (params.get("username") === null || params.get("password") === null) {
|
||||
return "";
|
||||
}
|
||||
@ -158,8 +161,17 @@ class App extends Component {
|
||||
}
|
||||
|
||||
getUrlWithoutQuery() {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
return location.toString().replace(location.search, "");
|
||||
return window.location.toString().replace(window.location.search, "");
|
||||
}
|
||||
|
||||
getLanguageParam(params) {
|
||||
// "/page?language=en"
|
||||
const language = params.get("language");
|
||||
if (language !== null) {
|
||||
Setting.setLanguage(language);
|
||||
return `language=${language}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
setLanguage(account) {
|
||||
@ -170,13 +182,23 @@ class App extends Component {
|
||||
}
|
||||
|
||||
getAccount() {
|
||||
let query = this.getAccessTokenParam();
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
|
||||
let query = this.getAccessTokenParam(params);
|
||||
if (query === "") {
|
||||
query = this.getCredentialParams();
|
||||
query = this.getCredentialParams(params);
|
||||
}
|
||||
|
||||
const query2 = this.getLanguageParam(params);
|
||||
if (query2 !== "") {
|
||||
const url = window.location.toString().replace(new RegExp(`[?&]${query2}`), "");
|
||||
window.history.replaceState({}, document.title, url);
|
||||
}
|
||||
|
||||
if (query !== "") {
|
||||
window.history.replaceState({}, document.title, this.getUrlWithoutQuery());
|
||||
}
|
||||
|
||||
AuthBackend.getAccount(query)
|
||||
.then((res) => {
|
||||
let account = null;
|
||||
@ -412,6 +434,13 @@ class App extends Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/products">
|
||||
<Link to="/products">
|
||||
{i18next.t("general:Products")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/payments">
|
||||
<Link to="/payments">
|
||||
@ -490,6 +519,9 @@ class App extends Component {
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/certs/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/products/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/products/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/payments/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)}/>
|
||||
|
@ -47,6 +47,7 @@ class ApplicationEditPage extends React.Component {
|
||||
certs: [],
|
||||
providers: [],
|
||||
uploading: false,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -60,6 +61,9 @@ class ApplicationEditPage extends React.Component {
|
||||
getApplication() {
|
||||
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
||||
.then((application) => {
|
||||
if (application.grantTypes === null || application.grantTypes.length === 0) {
|
||||
application.grantTypes = ["authorization_code"];
|
||||
}
|
||||
this.setState({
|
||||
application: application,
|
||||
});
|
||||
@ -134,9 +138,10 @@ class ApplicationEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("application:Edit Application")}
|
||||
{this.state.mode === "add" ? i18next.t("application:New Application") : i18next.t("application:Edit Application")}
|
||||
<Button onClick={() => this.submitApplicationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitApplicationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteApplication()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -161,12 +166,12 @@ class ApplicationEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel("Logo", i18next.t("general:Logo - Tooltip"))} :
|
||||
{Setting.getLabel("general:Logo", i18next.t("general:Logo - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} style={(Setting.isMobile()) ? {maxWidth:'100%'} :{}}>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
URL:
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<Input prefix={<LinkOutlined/>} value={this.state.application.logo} onChange={e => {
|
||||
@ -433,6 +438,26 @@ class ApplicationEditPage extends React.Component {
|
||||
</Popover>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Grant types"), i18next.t("application:Grant types - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}}
|
||||
value={this.state.application.grantTypes}
|
||||
onChange={(value => {
|
||||
this.updateApplicationField('grantTypes', value);
|
||||
})} >
|
||||
{
|
||||
[
|
||||
{id: "authorization_code", name: "Authorization Code"},
|
||||
{id: "password", name: "Password"},
|
||||
{id: "client_credentials", name: "Client Credentials"},
|
||||
].map((item, index)=><Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Providers"), i18next.t("general:Providers - Tooltip"))} :
|
||||
@ -492,13 +517,13 @@ class ApplicationEditPage extends React.Component {
|
||||
if (!Setting.isMobile()) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Col span={11} style={{display:'flex',flexDirection:'column'}}>
|
||||
<a style={{marginBottom: '10px',display:'flex'}} target="_blank" rel="noreferrer" href={signUpUrl}>
|
||||
<Col span={11} style={{display:"flex", flexDirection: "column"}}>
|
||||
<a style={{marginBottom: "10px", display: "flex"}} target="_blank" rel="noreferrer" href={signUpUrl}>
|
||||
<Button type="primary">{i18next.t("application:Test signup page..")}</Button>
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888" ,alignItems:'center',overflow:'auto',flexDirection:'column',flex:'auto'}}>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems:"center", overflow:"auto", flexDirection:"column", flex: "auto"}}>
|
||||
{
|
||||
this.state.application.enablePassword ? (
|
||||
<SignupPage application={this.state.application} />
|
||||
@ -508,13 +533,13 @@ class ApplicationEditPage extends React.Component {
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={11} style={{display:'flex',flexDirection:'column'}}>
|
||||
<a style={{marginBottom: '10px',display:'flex'}} target="_blank" rel="noreferrer" href={signInUrl}>
|
||||
<Col span={11} style={{display:"flex", flexDirection: "column"}}>
|
||||
<a style={{marginBottom: "10px", display: "flex"}} target="_blank" rel="noreferrer" href={signInUrl}>
|
||||
<Button type="primary">{i18next.t("application:Test signin page..")}</Button>
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888",alignItems:'center',overflow:'auto',flexDirection:'column',flex:'auto' }}>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems:"center", overflow:"auto", flexDirection:"column", flex: "auto"}}>
|
||||
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
|
||||
</div>
|
||||
</Col>
|
||||
@ -523,11 +548,11 @@ class ApplicationEditPage extends React.Component {
|
||||
} else{
|
||||
return(
|
||||
<React.Fragment>
|
||||
<Col span={24} style={{display:'flex',flexDirection:'column'}}>
|
||||
<a style={{marginBottom: '10px',display:'flex'}} target="_blank" rel="noreferrer" href={signUpUrl}>
|
||||
<Col span={24} style={{display:"flex", flexDirection: "column"}}>
|
||||
<a style={{marginBottom: "10px", display: "flex"}} target="_blank" rel="noreferrer" href={signUpUrl}>
|
||||
<Button type="primary">{i18next.t("application:Test signup page..")}</Button>
|
||||
</a>
|
||||
<div style={{marginBottom:'10px', width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888" ,alignItems:'center',overflow:'auto',flexDirection:'column',flex:'auto'}}>
|
||||
<div style={{marginBottom:"10px", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
{
|
||||
this.state.application.enablePassword ? (
|
||||
<SignupPage application={this.state.application} />
|
||||
@ -536,10 +561,10 @@ class ApplicationEditPage extends React.Component {
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<a style={{marginBottom: '10px',display:'flex'}} target="_blank" rel="noreferrer" href={signInUrl}>
|
||||
<a style={{marginBottom: "10px", display: "flex"}} target="_blank" rel="noreferrer" href={signInUrl}>
|
||||
<Button type="primary">{i18next.t("application:Test signin page..")}</Button>
|
||||
</a>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888",alignItems:'center',overflow:'auto',flexDirection:'column',flex:'auto' }}>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
|
||||
</div>
|
||||
</Col>
|
||||
@ -553,13 +578,13 @@ class ApplicationEditPage extends React.Component {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Col span={(Setting.isMobile()) ? 24 : 11} style={{display:'flex',flexDirection:'column',flex:'auto'}} >
|
||||
<a style={{marginBottom: '10px'}} target="_blank" rel="noreferrer" href={promptUrl}>
|
||||
<Col span={(Setting.isMobile()) ? 24 : 11} style={{display:"flex", flexDirection: "column", flex: "auto"}} >
|
||||
<a style={{marginBottom: "10px"}} target="_blank" rel="noreferrer" href={promptUrl}>
|
||||
<Button type="primary">{i18next.t("application:Test prompt page..")}</Button>
|
||||
</a>
|
||||
<br style={(Setting.isMobile()) ? {display:'none'} : {}} />
|
||||
<br style={(Setting.isMobile()) ? {display:'none'} : {}} />
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888",flexDirection:'column',flex:'auto'}}>
|
||||
<br style={(Setting.isMobile()) ? {display: "none"} : {}} />
|
||||
<br style={(Setting.isMobile()) ? {display: "none"} : {}} />
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", flexDirection: "column", flex: "auto"}}>
|
||||
<PromptPage application={this.state.application} account={this.props.account} />
|
||||
</div>
|
||||
</Col>
|
||||
@ -592,6 +617,16 @@ class ApplicationEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteApplication() {
|
||||
ApplicationBackend.deleteApplication(this.state.application)
|
||||
.then(() => {
|
||||
this.props.history.push(`/applications`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Application failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -601,6 +636,7 @@ class ApplicationEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitApplicationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitApplicationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteApplication()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
logo: "https://cdn.casdoor.com/logo/casdoor-logo_1185x256.png",
|
||||
enablePassword: true,
|
||||
enableSignUp: true,
|
||||
enableSigninSession: true,
|
||||
enableSigninSession: false,
|
||||
enableCodeSignin: false,
|
||||
providers: [],
|
||||
signupItems: [
|
||||
@ -58,8 +58,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
const newApplication = this.newApplication();
|
||||
ApplicationBackend.addApplication(newApplication)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Application added successfully`);
|
||||
this.props.history.push(`/applications/${newApplication.name}`);
|
||||
this.props.history.push({pathname: `/applications/${newApplication.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -30,6 +30,7 @@ class CertEditPage extends React.Component {
|
||||
classes: props,
|
||||
certName: props.match.params.certName,
|
||||
cert: null,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -67,9 +68,10 @@ class CertEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("cert:Edit Cert")}
|
||||
{this.state.mode === "add" ? i18next.t("cert:New Cert") : i18next.t("cert:Edit Cert")}
|
||||
<Button onClick={() => this.submitCertEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteCert()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -236,6 +238,16 @@ class CertEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteCert() {
|
||||
CertBackend.deleteCert(this.state.cert)
|
||||
.then(() => {
|
||||
this.props.history.push(`/certs`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -245,6 +257,7 @@ class CertEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitCertEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteCert()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -44,8 +44,7 @@ class CertListPage extends BaseListPage {
|
||||
const newCert = this.newCert();
|
||||
CertBackend.addCert(newCert)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Cert added successfully`);
|
||||
this.props.history.push(`/certs/${newCert.name}`);
|
||||
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -31,6 +31,7 @@ class OrganizationEditPage extends React.Component {
|
||||
organizationName: props.match.params.organizationName,
|
||||
organization: null,
|
||||
ldaps: null,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -84,9 +85,10 @@ class OrganizationEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("organization:Edit Organization")}
|
||||
{this.state.mode === "add" ? i18next.t("organization:New Organization") : i18next.t("organization:Edit Organization")}
|
||||
<Button onClick={() => this.submitOrganizationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitOrganizationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteOrganization()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -111,12 +113,12 @@ class OrganizationEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel("Favicon", i18next.t("general:Favicon - Tooltip"))} :
|
||||
{Setting.getLabel("general:Favicon", i18next.t("general:Favicon - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
URL:
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<Input prefix={<LinkOutlined/>} value={this.state.organization.favicon} onChange={e => {
|
||||
@ -186,7 +188,7 @@ class OrganizationEditPage extends React.Component {
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
URL:
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<Input prefix={<LinkOutlined/>} value={this.state.organization.defaultAvatar} onChange={e => {
|
||||
@ -269,6 +271,16 @@ class OrganizationEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteOrganization() {
|
||||
OrganizationBackend.deleteOrganization(this.state.organization)
|
||||
.then(() => {
|
||||
this.props.history.push(`/organizations`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -278,6 +290,7 @@ class OrganizationEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitOrganizationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitOrganizationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteOrganization()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -45,8 +45,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
const newOrganization = this.newOrganization();
|
||||
OrganizationBackend.addOrganization(newOrganization)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Organization added successfully`);
|
||||
this.props.history.push(`/organizations/${newOrganization.name}`);
|
||||
this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -13,15 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row, Select, Switch} from 'antd';
|
||||
import {Button, Card, Col, Input, Row} from 'antd';
|
||||
import * as PaymentBackend from "./backend/PaymentBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as UserBackend from "./backend/UserBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import * as RoleBackend from "./backend/RoleBackend";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class PaymentEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
@ -31,6 +26,7 @@ class PaymentEditPage extends React.Component {
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
paymentName: props.match.params.paymentName,
|
||||
payment: null,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -68,9 +64,10 @@ class PaymentEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("payment:Edit Payment")}
|
||||
{this.state.mode === "add" ? i18next.t("payment:New Payment") : i18next.t("payment:Edit Payment")}
|
||||
<Button onClick={() => this.submitPaymentEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitPaymentEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deletePayment()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -103,16 +100,6 @@ class PaymentEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.payment.name} onChange={e => {
|
||||
// this.updatePaymentField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Provider"), i18next.t("general:Provider - Tooltip"))} :
|
||||
@ -192,6 +179,16 @@ class PaymentEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deletePayment() {
|
||||
PaymentBackend.deletePayment(this.state.payment)
|
||||
.then(() => {
|
||||
this.props.history.push(`/payments`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Payment failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -201,6 +198,7 @@ class PaymentEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitPaymentEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitPaymentEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deletePayment()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Popconfirm, Switch, Table} from 'antd';
|
||||
import {Button, Popconfirm, Table} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as PaymentBackend from "./backend/PaymentBackend";
|
||||
@ -45,8 +45,7 @@ class PaymentListPage extends BaseListPage {
|
||||
const newPayment = this.newPayment();
|
||||
PaymentBackend.addPayment(newPayment)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Payment added successfully`);
|
||||
this.props.history.push(`/payments/${newPayment.name}`);
|
||||
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -34,6 +34,7 @@ class PermissionEditPage extends React.Component {
|
||||
organizations: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -102,9 +103,10 @@ class PermissionEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("permission:Edit Permission")}
|
||||
{this.state.mode === "add" ? i18next.t("permission:New Permission") : i18next.t("permission:Edit Permission")}
|
||||
<Button onClick={() => this.submitPermissionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deletePermission()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -258,6 +260,16 @@ class PermissionEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deletePermission() {
|
||||
PermissionBackend.deletePermission(this.state.permission)
|
||||
.then(() => {
|
||||
this.props.history.push(`/permissions`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -267,6 +279,7 @@ class PermissionEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitPermissionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deletePermission()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -43,8 +43,7 @@ class PermissionListPage extends BaseListPage {
|
||||
const newPermission = this.newPermission();
|
||||
PermissionBackend.addPermission(newPermission)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Permission added successfully`);
|
||||
this.props.history.push(`/permissions/${newPermission.owner}/${newPermission.name}`);
|
||||
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
196
web/src/ProductBuyPage.js
Normal file
196
web/src/ProductBuyPage.js
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Descriptions} from "antd";
|
||||
import i18next from "i18next";
|
||||
import * as ProductBackend from "./backend/ProductBackend";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
import * as Provider from "./auth/Provider";
|
||||
|
||||
class ProductBuyPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
productName: props.match?.params.productName,
|
||||
product: null,
|
||||
providers: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getProduct();
|
||||
this.getPaymentProviders();
|
||||
}
|
||||
|
||||
getProduct() {
|
||||
ProductBackend.getProduct("admin", this.state.productName)
|
||||
.then((product) => {
|
||||
this.setState({
|
||||
product: product,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getPaymentProviders() {
|
||||
ProviderBackend.getProviders("admin")
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
providers: res.filter(provider => provider.category === "Payment"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getProductObj() {
|
||||
if (this.props.product !== undefined) {
|
||||
return this.props.product;
|
||||
} else {
|
||||
return this.state.product;
|
||||
}
|
||||
}
|
||||
|
||||
getCurrencySymbol(product) {
|
||||
if (product?.currency === "USD") {
|
||||
return "$";
|
||||
} else if (product?.currency === "CNY") {
|
||||
return "¥";
|
||||
} else {
|
||||
return "(Unknown currency)";
|
||||
}
|
||||
}
|
||||
|
||||
getCurrencyText(product) {
|
||||
if (product?.currency === "USD") {
|
||||
return i18next.t("product:USD");
|
||||
} else if (product?.currency === "CNY") {
|
||||
return i18next.t("product:CNY");
|
||||
} else {
|
||||
return "(Unknown currency)";
|
||||
}
|
||||
}
|
||||
|
||||
getProviders(product) {
|
||||
if (this.state.providers.length === 0 || product.providers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let providerMap = {};
|
||||
this.state.providers.forEach(provider => {
|
||||
providerMap[provider.name] = provider;
|
||||
})
|
||||
|
||||
return product.providers.map(providerName => providerMap[providerName]);
|
||||
}
|
||||
|
||||
getPayUrl(product, provider) {
|
||||
if (product === null || provider === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `https://${provider.type}`;
|
||||
// if (provider.type === "WeChat") {
|
||||
// return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
|
||||
// } else if (provider.type === "GitHub") {
|
||||
// return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
|
||||
// }
|
||||
}
|
||||
|
||||
getPayButton(provider) {
|
||||
let text = provider.type;
|
||||
if (provider.type === "Alipay") {
|
||||
text = i18next.t("product:Alipay");
|
||||
} else if (provider.type === "WeChat Pay") {
|
||||
text = i18next.t("product:WeChat Pay");
|
||||
} else if (provider.type === "Paypal") {
|
||||
text = i18next.t("product:Paypal");
|
||||
}
|
||||
|
||||
return (
|
||||
<Button style={{height: "50px", borderWidth: "2px"}} shape="round" icon={
|
||||
<img style={{marginRight: "10px"}} width={36} height={36} src={Provider.getProviderLogo(provider)} alt={provider.displayName} />
|
||||
} size={"large"} >
|
||||
{
|
||||
text
|
||||
}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
renderProviderButton(provider, product) {
|
||||
return (
|
||||
<span key={provider.name} style={{width: "200px", marginRight: "20px", marginBottom: "10px"}}>
|
||||
<a style={{width: "200px"}} href={this.getPayUrl(product, provider)}>
|
||||
{
|
||||
this.getPayButton(provider)
|
||||
}
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
renderPay(product) {
|
||||
if (product === undefined || product === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (product.state !== "Published") {
|
||||
return i18next.t("product:This product is currently not in sale.");
|
||||
}
|
||||
if (product.providers.length === 0) {
|
||||
return i18next.t("product:There is no payment channel for this product.");
|
||||
}
|
||||
|
||||
const providers = this.getProviders(product);
|
||||
return providers.map(provider => {
|
||||
return this.renderProviderButton(provider, product);
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const product = this.getProductObj();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Descriptions title={i18next.t("product:Buy Product")} bordered>
|
||||
<Descriptions.Item label={i18next.t("general:Name")} span={3}>
|
||||
<span style={{fontSize: 28}}>
|
||||
{product?.displayName}
|
||||
</span>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Detail")}><span style={{fontSize: 16}}>{product?.detail}</span></Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Tag")}><span style={{fontSize: 16}}>{product?.tag}</span></Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:SKU")}><span style={{fontSize: 16}}>{product?.name}</span></Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Image")} span={3}>
|
||||
<img src={product?.image} alt={product?.image} height={90} style={{marginBottom: '20px'}}/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Price")}>
|
||||
<span style={{fontSize: 28, color: "red", fontWeight: "bold"}}>
|
||||
{`${this.getCurrencySymbol(product)}${product?.price} (${this.getCurrencyText(product)})`}
|
||||
</span>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Quantity")}><span style={{fontSize: 16}}>{product?.quantity}</span></Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Sold")}><span style={{fontSize: 16}}>{product?.sold}</span></Descriptions.Item>
|
||||
<Descriptions.Item label={i18next.t("product:Pay")} span={3}>
|
||||
{
|
||||
this.renderPay(product)
|
||||
}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ProductBuyPage;
|
311
web/src/ProductEditPage.js
Normal file
311
web/src/ProductEditPage.js
Normal file
@ -0,0 +1,311 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select} from 'antd';
|
||||
import * as ProductBackend from "./backend/ProductBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
import ProductBuyPage from "./ProductBuyPage";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class ProductEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
productName: props.match.params.productName,
|
||||
product: null,
|
||||
providers: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getProduct();
|
||||
this.getPaymentProviders();
|
||||
}
|
||||
|
||||
getProduct() {
|
||||
ProductBackend.getProduct("admin", this.state.productName)
|
||||
.then((product) => {
|
||||
this.setState({
|
||||
product: product,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getPaymentProviders() {
|
||||
ProviderBackend.getProviders("admin")
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
providers: res.filter(provider => provider.category === "Payment"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseProductField(key, value) {
|
||||
if ([""].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
updateProductField(key, value) {
|
||||
value = this.parseProductField(key, value);
|
||||
|
||||
let product = this.state.product;
|
||||
product[key] = value;
|
||||
this.setState({
|
||||
product: product,
|
||||
});
|
||||
}
|
||||
|
||||
renderProduct() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{this.state.mode === "add" ? i18next.t("product:New Product") : i18next.t("product:Edit Product")}
|
||||
<Button onClick={() => this.submitProductEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitProductEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteProduct()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.product.name} onChange={e => {
|
||||
this.updateProductField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.product.displayName} onChange={e => {
|
||||
this.updateProductField('displayName', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Image"), i18next.t("product:Image - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} style={(Setting.isMobile()) ? {maxWidth:'100%'} :{}}>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<Input prefix={<LinkOutlined/>} value={this.state.product.image} onChange={e => {
|
||||
this.updateProductField('image', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
{i18next.t("general:Preview")}:
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<a target="_blank" rel="noreferrer" href={this.state.product.image}>
|
||||
<img src={this.state.product.image} alt={this.state.product.image} height={90} style={{marginBottom: '20px'}}/>
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Tag"), i18next.t("product:Tag - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.product.tag} onChange={e => {
|
||||
this.updateProductField('tag', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Detail"), i18next.t("product:Detail - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.product.detail} onChange={e => {
|
||||
this.updateProductField('detail', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Currency"), i18next.t("product:Currency - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.product.currency} onChange={(value => {
|
||||
this.updateProductField('currency', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'USD', name: 'USD'},
|
||||
{id: 'CNY', name: 'CNY'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Price"), i18next.t("product:Price - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={this.state.product.price} onChange={value => {
|
||||
this.updateProductField('price', value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Quantity"), i18next.t("product:Quantity - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={this.state.product.quantity} onChange={value => {
|
||||
this.updateProductField('quantity', value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Sold"), i18next.t("product:Sold - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={this.state.product.sold} onChange={value => {
|
||||
this.updateProductField('sold', value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Payment providers"), i18next.t("product:Payment providers - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.product.providers} onChange={(value => {this.updateProductField('providers', value);})}>
|
||||
{
|
||||
this.state.providers.map((provider, index) => <Option key={index} value={provider.name}>{provider.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:State"), i18next.t("general:State - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.product.state} onChange={(value => {
|
||||
this.updateProductField('state', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'Published', name: 'Published'},
|
||||
{id: 'Draft', name: 'Draft'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Preview"), i18next.t("general:Preview - Tooltip"))} :
|
||||
</Col>
|
||||
{
|
||||
this.renderPreview()
|
||||
}
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
renderPreview() {
|
||||
let buyUrl = `/products/${this.state.product.name}/buy`;
|
||||
return (
|
||||
<Col span={22} style={{display: "flex", flexDirection: "column"}}>
|
||||
<a style={{marginBottom: "10px", display: "flex"}} target="_blank" rel="noreferrer" href={buyUrl}>
|
||||
<Button type="primary">{i18next.t("product:Test buy page..")}</Button>
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<div style={{width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<ProductBuyPage product={this.state.product} />
|
||||
</div>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
submitProductEdit(willExist) {
|
||||
let product = Setting.deepCopy(this.state.product);
|
||||
ProductBackend.updateProduct(this.state.product.owner, this.state.productName, product)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", `Successfully saved`);
|
||||
this.setState({
|
||||
productName: this.state.product.name,
|
||||
});
|
||||
|
||||
if (willExist) {
|
||||
this.props.history.push(`/products`);
|
||||
} else {
|
||||
this.props.history.push(`/products/${this.state.product.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
this.updateProductField('name', this.state.productName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProduct() {
|
||||
ProductBackend.deleteProduct(this.state.product)
|
||||
.then(() => {
|
||||
this.props.history.push(`/products`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.product !== null ? this.renderProduct() : null
|
||||
}
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitProductEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitProductEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteProduct()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProductEditPage;
|
295
web/src/ProductListPage.js
Normal file
295
web/src/ProductListPage.js
Normal file
@ -0,0 +1,295 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Col, List, Popconfirm, Row, Table, Tooltip} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as ProductBackend from "./backend/ProductBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import {EditOutlined} from "@ant-design/icons";
|
||||
|
||||
class ProductListPage extends BaseListPage {
|
||||
newProduct() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "admin",
|
||||
name: `product_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Product - ${randomName}`,
|
||||
image: "https://cdn.casdoor.com/logo/casdoor-logo_1185x256.png",
|
||||
tag: "Casdoor Summit 2022",
|
||||
currency: "USD",
|
||||
price: 300,
|
||||
quantity: 99,
|
||||
sold: 10,
|
||||
providers: [],
|
||||
state: "Published",
|
||||
}
|
||||
}
|
||||
|
||||
addProduct() {
|
||||
const newProduct = this.newProduct();
|
||||
ProductBackend.addProduct(newProduct)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProduct(i) {
|
||||
ProductBackend.deleteProduct(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Product deleted successfully`);
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(products) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '140px',
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('name'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/products/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
dataIndex: 'displayName',
|
||||
key: 'displayName',
|
||||
width: '170px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('displayName'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Image"),
|
||||
dataIndex: 'image',
|
||||
key: 'image',
|
||||
width: '170px',
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<a target="_blank" rel="noreferrer" href={text}>
|
||||
<img src={text} alt={text} width={150} />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Tag"),
|
||||
dataIndex: 'tag',
|
||||
key: 'tag',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('tag'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Currency"),
|
||||
dataIndex: 'currency',
|
||||
key: 'currency',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('currency'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Price"),
|
||||
dataIndex: 'price',
|
||||
key: 'price',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('price'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Quantity"),
|
||||
dataIndex: 'quantity',
|
||||
key: 'quantity',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('quantity'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Sold"),
|
||||
dataIndex: 'sold',
|
||||
key: 'sold',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('sold'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:State"),
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('state'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Payment providers"),
|
||||
dataIndex: 'providers',
|
||||
key: 'providers',
|
||||
width: '500px',
|
||||
...this.getColumnSearchProps('providers'),
|
||||
render: (text, record, index) => {
|
||||
const providers = text;
|
||||
if (providers.length === 0) {
|
||||
return "(empty)";
|
||||
}
|
||||
|
||||
const half = Math.floor((providers.length + 1) / 2);
|
||||
|
||||
const getList = (providers) => {
|
||||
return (
|
||||
<List
|
||||
size="small"
|
||||
locale={{emptyText: " "}}
|
||||
dataSource={providers}
|
||||
renderItem={(providerName, i) => {
|
||||
return (
|
||||
<List.Item>
|
||||
<div style={{display: "inline"}}>
|
||||
<Tooltip placement="topLeft" title="Edit">
|
||||
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/providers/${providerName}`)} />
|
||||
</Tooltip>
|
||||
<Link to={`/providers/${providerName}`}>
|
||||
{providerName}
|
||||
</Link>
|
||||
</div>
|
||||
</List.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
{
|
||||
getList(providers.slice(0, half))
|
||||
}
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
{
|
||||
getList(providers.slice(half))
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: '',
|
||||
key: 'op',
|
||||
width: '170px',
|
||||
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => this.props.history.push(`/products/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete product: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteProduct(index)}
|
||||
>
|
||||
<Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const paginationProps = {
|
||||
total: this.state.pagination.total,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table scroll={{x: 'max-content'}} columns={columns} dataSource={products} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Products")}
|
||||
<Button type="primary" size="small" onClick={this.addProduct.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
onChange={this.handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({ loading: true });
|
||||
ProductBackend.getProducts("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
pagination: {
|
||||
...params.pagination,
|
||||
total: res.data2,
|
||||
},
|
||||
searchText: params.searchText,
|
||||
searchedColumn: params.searchedColumn,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default ProductListPage;
|
@ -31,6 +31,7 @@ class ProviderEditPage extends React.Component {
|
||||
classes: props,
|
||||
providerName: props.match.params.providerName,
|
||||
provider: null,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -133,9 +134,10 @@ class ProviderEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("provider:Edit Provider")}
|
||||
{this.state.mode === "add" ? i18next.t("provider:New Provider") : i18next.t("provider:Edit Provider")}
|
||||
<Button onClick={() => this.submitProviderEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitProviderEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteProvider()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -293,6 +295,20 @@ class ProviderEditPage extends React.Component {
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
{
|
||||
this.state.provider.type !== "Adfs" ? null : (
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.domain} onChange={e => {
|
||||
this.updateProviderField('domain', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
{this.state.provider.category === "Storage" ? (
|
||||
<div>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
@ -558,6 +574,16 @@ class ProviderEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteProvider() {
|
||||
ProviderBackend.deleteProvider(this.state.provider)
|
||||
.then(() => {
|
||||
this.props.history.push(`/providers`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Provider failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -567,6 +593,7 @@ class ProviderEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitProviderEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitProviderEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteProvider()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -47,8 +47,7 @@ class ProviderListPage extends BaseListPage {
|
||||
const newProvider = this.newProvider();
|
||||
ProviderBackend.addProvider(newProvider)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Provider added successfully`);
|
||||
this.props.history.push(`/providers/${newProvider.name}`);
|
||||
this.props.history.push({pathname: `/providers/${newProvider.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -33,6 +33,7 @@ class RoleEditPage extends React.Component {
|
||||
organizations: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -101,9 +102,10 @@ class RoleEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("role:Edit Role")}
|
||||
{this.state.mode === "add" ? i18next.t("role:New Role") : i18next.t("role:Edit Role")}
|
||||
<Button onClick={() => this.submitRoleEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitRoleEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteRole()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -201,6 +203,16 @@ class RoleEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteRole() {
|
||||
RoleBackend.deleteRole(this.state.role)
|
||||
.then(() => {
|
||||
this.props.history.push(`/roles`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -210,6 +222,7 @@ class RoleEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitRoleEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitRoleEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteRole()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -39,8 +39,7 @@ class RoleListPage extends BaseListPage {
|
||||
const newRole = this.newRole();
|
||||
RoleBackend.addRole(newRole)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Role added successfully`);
|
||||
this.props.history.push(`/roles/${newRole.owner}/${newRole.name}`);
|
||||
this.props.history.push({pathname: `/roles/${newRole.owner}/${newRole.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -325,6 +325,10 @@ export function getAvatarColor(s) {
|
||||
return colorList[random % 4];
|
||||
}
|
||||
|
||||
export function getLanguage() {
|
||||
return i18next.language;
|
||||
}
|
||||
|
||||
export function setLanguage(language) {
|
||||
localStorage.setItem("language", language);
|
||||
changeMomentLanguage(language);
|
||||
@ -398,6 +402,7 @@ export function getProviderTypeOptions(category) {
|
||||
{id: 'WeCom', name: 'WeCom'},
|
||||
{id: 'Lark', name: 'Lark'},
|
||||
{id: 'GitLab', name: 'GitLab'},
|
||||
{id: 'Adfs', name: 'Adfs'},
|
||||
{id: 'Baidu', name: 'Baidu'},
|
||||
{id: 'Infoflow', name: 'Infoflow'},
|
||||
{id: 'Apple', name: 'Apple'},
|
||||
|
@ -170,7 +170,8 @@ class SignupTable extends React.Component {
|
||||
} if (record.name === "Display name") {
|
||||
options = [
|
||||
{id: 'None', name: 'None'},
|
||||
{id: 'Personal', name: 'Personal'},
|
||||
{id: 'Real name', name: 'Real name'},
|
||||
{id: 'First, last', name: 'First, last'},
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ class SyncerEditPage extends React.Component {
|
||||
syncerName: props.match.params.syncerName,
|
||||
syncer: null,
|
||||
organizations: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -83,9 +84,10 @@ class SyncerEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("syncer:Edit Syncer")}
|
||||
{this.state.mode === "add" ? i18next.t("syncer:New Syncer") : i18next.t("syncer:Edit Syncer")}
|
||||
<Button onClick={() => this.submitSyncerEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitSyncerEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteSyncer()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -308,6 +310,16 @@ class SyncerEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteSyncer() {
|
||||
SyncerBackend.deleteSyncer(this.state.syncer)
|
||||
.then(() => {
|
||||
this.props.history.push(`/syncers`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Syncer failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -317,6 +329,7 @@ class SyncerEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitSyncerEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitSyncerEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteSyncer()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -50,8 +50,7 @@ class SyncerListPage extends BaseListPage {
|
||||
const newSyncer = this.newSyncer();
|
||||
SyncerBackend.addSyncer(newSyncer)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Syncer added successfully`);
|
||||
this.props.history.push(`/syncers/${newSyncer.name}`);
|
||||
this.props.history.push({pathname: `/syncers/${newSyncer.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -25,6 +25,7 @@ class TokenEditPage extends React.Component {
|
||||
classes: props,
|
||||
tokenName: props.match.params.tokenName,
|
||||
token: null,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -62,9 +63,10 @@ class TokenEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("token:Edit Token")}
|
||||
{this.state.mode === "add" ? i18next.t("token:New Token") : i18next.t("token:Edit Token")}
|
||||
<Button onClick={() => this.submitTokenEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitTokenEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteToken()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -186,6 +188,16 @@ class TokenEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteToken() {
|
||||
TokenBackend.deleteToken(this.state.token)
|
||||
.then(() => {
|
||||
this.props.history.push(`/tokens`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Token failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -195,6 +207,7 @@ class TokenEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitTokenEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitTokenEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteToken()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -44,8 +44,7 @@ class TokenListPage extends BaseListPage {
|
||||
const newToken = this.newToken();
|
||||
TokenBackend.addToken(newToken)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Token added successfully`);
|
||||
this.props.history.push(`/tokens/${newToken.name}`);
|
||||
this.props.history.push({pathname: `/tokens/${newToken.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -46,6 +46,7 @@ class UserEditPage extends React.Component {
|
||||
application: null,
|
||||
organizations: [],
|
||||
applications: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -121,9 +122,10 @@ class UserEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("user:Edit User")}
|
||||
{this.state.mode === "add" ? i18next.t("user:New User") : i18next.t("user:Edit User")}
|
||||
<Button onClick={() => this.submitUserEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitUserEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteUser()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -430,6 +432,16 @@ class UserEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteUser() {
|
||||
UserBackend.deleteUser(this.state.user)
|
||||
.then(() => {
|
||||
this.props.history.push(`/users`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `User failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -439,6 +451,7 @@ class UserEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitUserEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitUserEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteUser()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -21,6 +21,7 @@ import * as Setting from "./Setting";
|
||||
import * as UserBackend from "./backend/UserBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as path from "path";
|
||||
|
||||
class UserListPage extends BaseListPage {
|
||||
constructor(props) {
|
||||
@ -69,8 +70,7 @@ class UserListPage extends BaseListPage {
|
||||
const newUser = this.newUser();
|
||||
UserBackend.addUser(newUser)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `User added successfully`);
|
||||
this.props.history.push(`/users/${newUser.owner}/${newUser.name}`);
|
||||
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -96,6 +96,7 @@ class WebhookEditPage extends React.Component {
|
||||
webhookName: props.match.params.webhookName,
|
||||
webhook: null,
|
||||
organizations: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
@ -149,9 +150,10 @@ class WebhookEditPage extends React.Component {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("webhook:Edit Webhook")}
|
||||
{this.state.mode === "add" ? i18next.t("webhook:New Webhook") : i18next.t("webhook:Edit Webhook")}
|
||||
<Button onClick={() => this.submitWebhookEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitWebhookEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} onClick={() => this.deleteWebhook()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
@ -315,6 +317,16 @@ class WebhookEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
deleteWebhook() {
|
||||
WebhookBackend.deleteWebhook(this.state.webhook)
|
||||
.then(() => {
|
||||
this.props.history.push(`/webhooks`);
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Webhook failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -324,6 +336,7 @@ class WebhookEditPage extends React.Component {
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitWebhookEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitWebhookEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: '20px'}} size="large" onClick={() => this.deleteWebhook()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -42,8 +42,7 @@ class WebhookListPage extends BaseListPage {
|
||||
const newWebhook = this.newWebhook();
|
||||
WebhookBackend.addWebhook(newWebhook)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Webhook added successfully`);
|
||||
this.props.history.push(`/webhooks/${newWebhook.name}`);
|
||||
this.props.history.push({pathname: `/webhooks/${newWebhook.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
|
@ -18,7 +18,7 @@ import UserEditPage from "../UserEditPage";
|
||||
class AccountPage extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<UserEditPage organizationName={this.props.account.owner} userName={this.props.account.name} account={this.props.account} />
|
||||
<UserEditPage organizationName={this.props.account.owner} userName={this.props.account.name} account={this.props.account} location={this.props.location} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
32
web/src/auth/AdfsLoginButton.js
Normal file
32
web/src/auth/AdfsLoginButton.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
import {createButton} from "react-social-login-buttons";
|
||||
import {StaticBaseUrl} from "../Setting";
|
||||
|
||||
function Icon({ width = 24, height = 24, color }) {
|
||||
return <img src={`${StaticBaseUrl}/buttons/adfs.svg`} alt="Sign in with ADFS" style={{width: 24, height: 24}} />;
|
||||
}
|
||||
|
||||
const config = {
|
||||
text: "Sign in with ADFS",
|
||||
icon: Icon,
|
||||
iconFormat: name => `fa fa-${name}`,
|
||||
style: {background: "#ffffff", color: "#000000"},
|
||||
activeStyle: {background: "#ededee"},
|
||||
};
|
||||
|
||||
const AdfsLoginButton = createButton(config);
|
||||
|
||||
export default AdfsLoginButton;
|
@ -34,6 +34,7 @@ import LinkedInLoginButton from "./LinkedInLoginButton";
|
||||
import WeComLoginButton from "./WeComLoginButton";
|
||||
import LarkLoginButton from "./LarkLoginButton";
|
||||
import GitLabLoginButton from "./GitLabLoginButton";
|
||||
import AdfsLoginButton from "./AdfsLoginButton";
|
||||
import BaiduLoginButton from "./BaiduLoginButton";
|
||||
import InfoflowLoginButton from "./InfoflowLoginButton";
|
||||
import AppleLoginButton from "./AppleLoginButton"
|
||||
@ -188,6 +189,8 @@ class LoginPage extends React.Component {
|
||||
return <LarkLoginButton text={text} align={"center"} />
|
||||
} else if (type === "GitLab") {
|
||||
return <GitLabLoginButton text={text} align={"center"} />
|
||||
} else if (type === "Adfs") {
|
||||
return <AdfsLoginButton text={text} align={"center"} />
|
||||
} else if (type === "Baidu") {
|
||||
return <BaiduLoginButton text={text} align={"center"} />
|
||||
} else if (type === "Infoflow") {
|
||||
|
@ -70,6 +70,10 @@ const authInfo = {
|
||||
scope: "read_user+profile",
|
||||
endpoint: "https://gitlab.com/oauth/authorize",
|
||||
},
|
||||
Adfs: {
|
||||
scope: "openid",
|
||||
endpoint: "http://example.com",
|
||||
},
|
||||
Baidu: {
|
||||
scope: "basic",
|
||||
endpoint: "http://openapi.baidu.com/oauth/2.0/authorize",
|
||||
@ -267,6 +271,8 @@ export function getAuthUrl(application, provider, method) {
|
||||
return `${endpoint}?app_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}`;
|
||||
} else if (provider.type === "GitLab") {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
|
||||
} else if (provider.type === "Adfs") {
|
||||
return `${provider.domain}/adfs/oauth2/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&nonce=casdoor&scope=openid`;
|
||||
} else if (provider.type === "Baidu") {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
|
||||
} else if (provider.type === "Infoflow"){
|
||||
|
@ -192,15 +192,50 @@ class SignupPage extends React.Component {
|
||||
</Form.Item>
|
||||
)
|
||||
} else if (signupItem.name === "Display name") {
|
||||
if (signupItem.rule === "First, last" && Setting.getLanguage() !== "zh") {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Form.Item
|
||||
name="firstName"
|
||||
key="firstName"
|
||||
label={i18next.t("general:First name")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: i18next.t("signup:Please input your first name!"),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="lastName"
|
||||
key="lastName"
|
||||
label={i18next.t("general:Last name")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: i18next.t("signup:Please input your last name!"),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
name="name"
|
||||
key="name"
|
||||
label={signupItem.rule === "Personal" ? i18next.t("general:Personal name") : i18next.t("general:Display name")}
|
||||
label={(signupItem.rule === "Real name" || signupItem.rule === "First, last") ? i18next.t("general:Real name") : i18next.t("general:Display name")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: signupItem.rule === "Personal" ? i18next.t("signup:Please input your personal name!") : i18next.t("signup:Please input your display name!"),
|
||||
message: (signupItem.rule === "Real name" || signupItem.rule === "First, last") ? i18next.t("signup:Please input your real name!") : i18next.t("signup:Please input your display name!"),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
|
56
web/src/backend/ProductBackend.js
Normal file
56
web/src/backend/ProductBackend.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getProducts(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-products?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getProduct(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-product?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updateProduct(owner, name, product) {
|
||||
let newProduct = Setting.deepCopy(product);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-product?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newProduct),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addProduct(product) {
|
||||
let newProduct = Setting.deepCopy(product);
|
||||
return fetch(`${Setting.ServerUrl}/api/add-product`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newProduct),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deleteProduct(product) {
|
||||
let newProduct = Setting.deepCopy(product);
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-product`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newProduct),
|
||||
}).then(res => res.json());
|
||||
}
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "Anmeldung aktivieren",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "Datei erfolgreich hochgeladen",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "Passwort AN",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Zitat bearbeiten",
|
||||
"Expire in years": "Gültig in Jahren",
|
||||
"Expire in years - Tooltip": "Verfällt in Jahren - Tooltip",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Privater Schlüssel",
|
||||
"Private key - Tooltip": "Privater Schlüssel - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Privater Schlüssel erfolgreich in die Zwischenablage kopiert",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Zurück zu Hause",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "E-Mail",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
"Forget URL": "URL vergessen",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Zuhause",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "Ist aktiviert - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master-Passwort",
|
||||
"Master password - Tooltip": "Masterpasswort - Tooltip",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "Berechtigungen",
|
||||
"Personal name": "Persönlicher Name",
|
||||
"Phone": "Telefon",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Telefonpräfix",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Vorschau",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Products": "Products",
|
||||
"Provider": "Anbieter",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "Anbieter",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Real name": "Persönlicher Name",
|
||||
"Records": "Datensätze",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Ressourcen",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Zeitstempel",
|
||||
"Tokens": "Token",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "Hoch",
|
||||
"User": "Benutzer",
|
||||
"User - Tooltip": "Benutzer - Tooltip",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "Standard Avatar",
|
||||
"Edit Organization": "Organisation bearbeiten",
|
||||
"Favicon": "Févicon",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "Weiche Löschung",
|
||||
"Soft deletion - Tooltip": "Weiche Löschung - Tooltip",
|
||||
"Website URL": "Website-URL",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Aktionen",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "Berechtigung bearbeiten",
|
||||
"Effect": "Effekt",
|
||||
"Effect - Tooltip": "Effekt - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "Ressourcentyp",
|
||||
"Resource type - Tooltip": "Ressourcentyp - Tooltip",
|
||||
"Resources": "Ressourcen"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Zugangsschlüssel",
|
||||
"Access key - Tooltip": "Zugriffsschlüssel - Tooltip",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "Methode",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Metadaten erfolgreich analysieren",
|
||||
"Port": "Port",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Rolle bearbeiten",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "Unterrollen",
|
||||
"Sub roles - Tooltip": "Unterrollen - Tooltip",
|
||||
"Sub users": "Unternutzer",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "Bitte geben Sie Ihre Adresse ein!",
|
||||
"Please input your affiliation!": "Bitte geben Sie Ihre Zugehörigkeit ein!",
|
||||
"Please input your display name!": "Bitte geben Sie Ihren Anzeigenamen ein!",
|
||||
"Please input your personal name!": "Bitte geben Sie Ihren persönlichen Namen ein!",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "Bitte geben Sie Ihre Telefonnummer ein!",
|
||||
"Please input your real name!": "Bitte geben Sie Ihren persönlichen Namen ein!",
|
||||
"Please select your country/region!": "Bitte wählen Sie Ihr Land/Ihre Region!",
|
||||
"Terms of Use": "Nutzungsbedingungen",
|
||||
"The input is not valid Email!": "Die Eingabe ist ungültig!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Ist gehasht",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "Sync-Intervall",
|
||||
"Sync interval - Tooltip": "Sync-Intervall - Tooltip",
|
||||
"Table": "Tisch",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "Autorisierungscode",
|
||||
"Edit Token": "Token bearbeiten",
|
||||
"Expires in": "Läuft ab",
|
||||
"New Token": "New Token",
|
||||
"Scope": "Bereich",
|
||||
"Token type": "Token-Typ"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "Passwort ändern...",
|
||||
"New Email": "Neue E-Mail",
|
||||
"New Password": "Neues Passwort",
|
||||
"New User": "New User",
|
||||
"New phone": "Neues Telefon",
|
||||
"OK": "Ok",
|
||||
"Old Password": "Altes Passwort",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "Methode",
|
||||
"Method - Tooltip": "Methode - Tooltip",
|
||||
"Name": "Name",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Wert"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "Enable signup",
|
||||
"Enable signup - Tooltip": "Enable signup - Tooltip",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "Password ON",
|
||||
"Password ON - Tooltip": "Password ON - Tooltip",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Edit Cert",
|
||||
"Expire in years": "Expire in years",
|
||||
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Avatar - Tooltip",
|
||||
"Back Home": "Back Home",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Email - Tooltip",
|
||||
"Favicon - Tooltip": "Favicon - Tooltip",
|
||||
"First name": "First name",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL - Tooltip": "Forget URL - Tooltip",
|
||||
"Home": "Home",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "Logo - Tooltip",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "Password type - Tooltip",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone - Tooltip",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix - Tooltip": "Phone prefix - Tooltip",
|
||||
"Preview": "Preview",
|
||||
"Preview - Tooltip": "Preview - Tooltip",
|
||||
"Products": "Products",
|
||||
"Provider": "Provider",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "Providers",
|
||||
"Providers - Tooltip": "Providers - Tooltip",
|
||||
"Real name": "Real name",
|
||||
"Records": "Records",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Favicon": "Favicon",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Website URL": "Website URL",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Port": "Port",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please input your real name!": "Please input your real name!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"New Token": "New Token",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New User": "New User",
|
||||
"New phone": "New phone",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "Activer l'inscription",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "Fichier téléchargé avec succès",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "Mot de passe activé",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Modifier le certificat",
|
||||
"Expire in years": "Expire dans les années",
|
||||
"Expire in years - Tooltip": "Expire dans les années - infobulle",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Clé privée",
|
||||
"Private key - Tooltip": "Clé privée - Infobulle",
|
||||
"Private key copied to clipboard successfully": "Clé privée copiée dans le presse-papiers avec succès",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "Avatars",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Retour à la page d'accueil",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "Courriel",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
"Forget URL": "Oublier l'URL",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Domicile",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "Est activé - infobulle",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Infobulle",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Mot de passe maître",
|
||||
"Master password - Tooltip": "Mot de passe maître - Infobulle",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Nom personnel",
|
||||
"Phone": "Téléphone",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Préfixe du téléphone",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Aperçu",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Products": "Products",
|
||||
"Provider": "Fournisseur",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "Fournisseurs",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Real name": "Nom personnel",
|
||||
"Records": "Enregistrements",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Ressource",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Synchronisateurs",
|
||||
"Timestamp": "Horodatage",
|
||||
"Tokens": "Jetons",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "Monter",
|
||||
"User": "Utilisateur",
|
||||
"User - Tooltip": "Utilisateur - infobulle",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "Avatar par défaut",
|
||||
"Edit Organization": "Modifier l'organisation",
|
||||
"Favicon": "Favicon",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "Suppression du logiciel",
|
||||
"Soft deletion - Tooltip": "Suppression de soft - infobulle",
|
||||
"Website URL": "URL du site web",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "Autorisation d'édition",
|
||||
"Effect": "Effet",
|
||||
"Effect - Tooltip": "Effet - Infobulle",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "Type de ressource",
|
||||
"Resource type - Tooltip": "Type de ressource - infobulle",
|
||||
"Resources": "Ressource"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Clé d'accès",
|
||||
"Access key - Tooltip": "Touche d'accès - Infobulle",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "Méthode",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Nom",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Analyse des métadonnées réussie",
|
||||
"Port": "Port",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Modifier le rôle",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "Sous-rôles",
|
||||
"Sub roles - Tooltip": "Sous-rôles - infobulle",
|
||||
"Sub users": "Sous-utilisateurs",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "Veuillez saisir votre adresse !",
|
||||
"Please input your affiliation!": "Veuillez entrer votre affiliation !",
|
||||
"Please input your display name!": "Veuillez entrer votre nom d'affichage !",
|
||||
"Please input your personal name!": "Veuillez entrer votre nom personnel !",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "Veuillez entrer votre numéro de téléphone!",
|
||||
"Please input your real name!": "Veuillez entrer votre nom personnel !",
|
||||
"Please select your country/region!": "Veuillez sélectionner votre pays/région!",
|
||||
"Terms of Use": "Conditions d'utilisation",
|
||||
"The input is not valid Email!": "L'entrée n'est pas un email valide !",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Est haché",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "Intervalle de synchronisation",
|
||||
"Sync interval - Tooltip": "Intervalle de synchronisation - infobulle",
|
||||
"Table": "Tableau",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "Code d'autorisation",
|
||||
"Edit Token": "Modifier le jeton",
|
||||
"Expires in": "Expire dans",
|
||||
"New Token": "New Token",
|
||||
"Scope": "Périmètre d'application",
|
||||
"Token type": "Type de jeton"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "Modifier le mot de passe...",
|
||||
"New Email": "Nouvel e-mail",
|
||||
"New Password": "Nouveau mot de passe",
|
||||
"New User": "New User",
|
||||
"New phone": "Nouveau téléphone",
|
||||
"OK": "Ok",
|
||||
"Old Password": "Ancien mot de passe",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "Méthode",
|
||||
"Method - Tooltip": "Méthode - Infobulle",
|
||||
"Name": "Nom",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Info-bulle",
|
||||
"Value": "Valeur"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "サインアップを有効にする",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "ファイルが正常にアップロードされました",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "パスワードON",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "HTMLファイルを選択してください",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Certを編集",
|
||||
"Expire in years": "有効期限",
|
||||
"Expire in years - Tooltip": "年間有効期限 - ツールチップ",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "秘密鍵を正常にクリップボードにコピーしました",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "アバター",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "ホーム",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "Eメールアドレス",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
"Forget URL": "URLを忘れた",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "ホーム",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "有効にする - ツールチップ",
|
||||
"LDAPs": "LDAP",
|
||||
"LDAPs - Tooltip": "LDAP - ツールチップ",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "マスターパスワード",
|
||||
"Master password - Tooltip": "マスターパスワード - ツールチップ",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "アクセス許可",
|
||||
"Personal name": "個人名",
|
||||
"Phone": "電話番号",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "電話プレフィクス",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "プレビュー",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Products": "Products",
|
||||
"Provider": "プロバイダー",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "プロバイダー",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Real name": "個人名",
|
||||
"Records": "レコード",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "リソース",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "タイムスタンプ",
|
||||
"Tokens": "トークン",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "上へ",
|
||||
"User": "ユーザー",
|
||||
"User - Tooltip": "ユーザー → ツールチップ",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "デフォルトのアバター",
|
||||
"Edit Organization": "組織を編集",
|
||||
"Favicon": "ファビコン",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "ソフト削除",
|
||||
"Soft deletion - Tooltip": "ソフト削除 - ツールチップ",
|
||||
"Website URL": "Website URL",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "アクション",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "権限を編集",
|
||||
"Effect": "効果",
|
||||
"Effect - Tooltip": "エフェクト - ツールチップ",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "リソースタイプ",
|
||||
"Resource type - Tooltip": "リソースタイプ - ツールチップ",
|
||||
"Resources": "リソース"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "アクセスキー",
|
||||
"Access key - Tooltip": "アクセスキー → ツールチップ",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "名前",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "メタデータの解析に成功",
|
||||
"Port": "ポート",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "役割を編集",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "サブロール",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "サブユーザー",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "住所を入力してください!",
|
||||
"Please input your affiliation!": "所属を入力してください!",
|
||||
"Please input your display name!": "表示名を入力してください。",
|
||||
"Please input your personal name!": "個人名を入力してください!",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "電話番号を入力してください!",
|
||||
"Please input your real name!": "個人名を入力してください!",
|
||||
"Please select your country/region!": "あなたの国/地域を選択してください!",
|
||||
"Terms of Use": "利用規約",
|
||||
"The input is not valid Email!": "入力されたメールアドレスが無効です!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "ハッシュされました",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "同期間隔",
|
||||
"Sync interval - Tooltip": "同期間隔 - ツールチップ",
|
||||
"Table": "表",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "認証コード",
|
||||
"Edit Token": "トークンを編集",
|
||||
"Expires in": "有効期限:",
|
||||
"New Token": "New Token",
|
||||
"Scope": "スコープ",
|
||||
"Token type": "トークンの種類"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "パスワードを変更...",
|
||||
"New Email": "新しいメール",
|
||||
"New Password": "新しいパスワード",
|
||||
"New User": "New User",
|
||||
"New phone": "新しい電話番号",
|
||||
"OK": "OK",
|
||||
"Old Password": "古いパスワード",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "方法 - ツールチップ",
|
||||
"Name": "名前",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL → ツールチップ",
|
||||
"Value": "値"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "Enable signup",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "Password ON",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Edit Cert",
|
||||
"Expire in years": "Expire in years",
|
||||
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Home",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Preview",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Products": "Products",
|
||||
"Provider": "Provider",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "Providers",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Real name": "Real name",
|
||||
"Records": "Records",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Favicon": "Favicon",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Website URL": "Website URL",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Port": "Port",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please input your real name!": "Please input your real name!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"New Token": "New Token",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New User": "New User",
|
||||
"New phone": "New phone",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "Включить регистрацию",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "Файл успешно загружен",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "Grant types - Tooltip",
|
||||
"New Application": "New Application",
|
||||
"Password ON": "Пароль ВКЛ",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Пожалуйста, выберите HTML-файл",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "Изменить сертификат",
|
||||
"Expire in years": "Истекает через годы",
|
||||
"Expire in years - Tooltip": "Истекает через годы - Подсказка",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Приватный ключ",
|
||||
"Private key - Tooltip": "Приватный ключ - Подсказка",
|
||||
"Private key copied to clipboard successfully": "Приватный ключ скопирован в буфер обмена",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "Аватар",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Назад",
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Капча",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "Cert - Tooltip",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "Почта",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
"Forget URL": "Забыть URL",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Домашний",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "Включено - Подсказка",
|
||||
"LDAPs": "LDAPы",
|
||||
"LDAPs - Tooltip": "LDAPs - Подсказки",
|
||||
"Last name": "Last name",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Мастер-пароль",
|
||||
"Master password - Tooltip": "Мастер-пароль - Tooltip",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Payments": "Payments",
|
||||
"Permissions": "Права доступа",
|
||||
"Personal name": "Личное имя",
|
||||
"Phone": "Телефон",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Префикс телефона",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Предпросмотр",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Products": "Products",
|
||||
"Provider": "Поставщик",
|
||||
"Provider - Tooltip": "Provider - Tooltip",
|
||||
"Providers": "Поставщики",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Real name": "Личное имя",
|
||||
"Records": "Отчеты",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Ресурсы",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Синхронизаторы",
|
||||
"Timestamp": "Отметка времени",
|
||||
"Tokens": "Жетоны",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Up": "Вверх",
|
||||
"User": "Пользователь",
|
||||
"User - Tooltip": "Пользователь - Подсказка",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "Аватар по умолчанию",
|
||||
"Edit Organization": "Изменить организацию",
|
||||
"Favicon": "Иконка",
|
||||
"New Organization": "New Organization",
|
||||
"Soft deletion": "Мягкое удаление",
|
||||
"Soft deletion - Tooltip": "Мягкое удаление - Подсказка",
|
||||
"Website URL": "URL сайта",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Edit Payment": "Edit Payment",
|
||||
"Good": "Good",
|
||||
"Good - Tooltip": "Good - Tooltip"
|
||||
"Good - Tooltip": "Good - Tooltip",
|
||||
"New Payment": "New Payment"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Действия",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "Изменить права доступа",
|
||||
"Effect": "Эффект",
|
||||
"Effect - Tooltip": "Эффект - Подсказка",
|
||||
"New Permission": "New Permission",
|
||||
"Resource type": "Тип ресурса",
|
||||
"Resource type - Tooltip": "Тип ресурса - Подсказка",
|
||||
"Resources": "Ресурсы"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Currency": "Currency",
|
||||
"Currency - Tooltip": "Currency - Tooltip",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail - Tooltip",
|
||||
"Edit Product": "Edit Product",
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image - Tooltip",
|
||||
"New Product": "New Product",
|
||||
"Pay": "Pay",
|
||||
"Payment providers": "Payment providers",
|
||||
"Payment providers - Tooltip": "Payment providers - Tooltip",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "Price",
|
||||
"Price - Tooltip": "Price - Tooltip",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity - Tooltip",
|
||||
"SKU": "SKU",
|
||||
"Sold": "Sold",
|
||||
"Sold - Tooltip": "Sold - Tooltip",
|
||||
"Tag": "Tag",
|
||||
"Tag - Tooltip": "Tag - Tooltip",
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Ключ доступа",
|
||||
"Access key - Tooltip": "Ключ доступа - Подсказка",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "Метод",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Наименование",
|
||||
"New Provider": "New Provider",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Анализ метаданных успешно завершен",
|
||||
"Port": "Порт",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Изменить роль",
|
||||
"New Role": "New Role",
|
||||
"Sub roles": "Суб роли",
|
||||
"Sub roles - Tooltip": "Суб роли - Tooltip",
|
||||
"Sub users": "Субпользователи",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "Пожалуйста, введите ваш адрес!",
|
||||
"Please input your affiliation!": "Пожалуйста, введите вашу партнерство!",
|
||||
"Please input your display name!": "Пожалуйста, введите ваше отображаемое имя!",
|
||||
"Please input your personal name!": "Пожалуйста, введите ваше личное имя!",
|
||||
"Please input your first name!": "Please input your first name!",
|
||||
"Please input your last name!": "Please input your last name!",
|
||||
"Please input your phone number!": "Пожалуйста, введите ваш номер телефона!",
|
||||
"Please input your real name!": "Пожалуйста, введите ваше личное имя!",
|
||||
"Please select your country/region!": "Пожалуйста, выберите вашу страну/регион!",
|
||||
"Terms of Use": "Условия использования",
|
||||
"The input is not valid Email!": "Ввод не является допустимым Email!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Хэшировано",
|
||||
"New Syncer": "New Syncer",
|
||||
"Sync interval": "Интервал синхронизации",
|
||||
"Sync interval - Tooltip": "Интервал синхронизации - Tooltip",
|
||||
"Table": "Таблица",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "Код авторизации",
|
||||
"Edit Token": "Изменить токен",
|
||||
"Expires in": "Истекает через",
|
||||
"New Token": "New Token",
|
||||
"Scope": "Сфера охвата",
|
||||
"Token type": "Тип токена"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "Изменить пароль...",
|
||||
"New Email": "Новое письмо",
|
||||
"New Password": "Новый пароль",
|
||||
"New User": "New User",
|
||||
"New phone": "Новый телефон",
|
||||
"OK": "ОК",
|
||||
"Old Password": "Старый пароль",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "Метод",
|
||||
"Method - Tooltip": "Метод - Подсказка",
|
||||
"Name": "Наименование",
|
||||
"New Webhook": "New Webhook",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Подсказка",
|
||||
"Value": "Значение"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"Enable signup": "启用注册",
|
||||
"Enable signup - Tooltip": "是否允许用户注册",
|
||||
"File uploaded successfully": "文件上传成功",
|
||||
"Grant types": "Grant types",
|
||||
"Grant types - Tooltip": "选择允许哪些OAuth协议中的Grant types",
|
||||
"New Application": "添加应用",
|
||||
"Password ON": "开启密码",
|
||||
"Password ON - Tooltip": "是否允许密码登录",
|
||||
"Please select a HTML file": "请选择一个HTML文件",
|
||||
@ -45,6 +48,7 @@
|
||||
"Edit Cert": "编辑证书",
|
||||
"Expire in years": "有效期(年)",
|
||||
"Expire in years - Tooltip": "到期年份-工具提示",
|
||||
"New Cert": "添加证书",
|
||||
"Private key": "私钥",
|
||||
"Private key - Tooltip": "私钥 - 工具提示",
|
||||
"Private key copied to clipboard successfully": "私钥已成功复制到剪贴板",
|
||||
@ -91,6 +95,7 @@
|
||||
"Avatar": "头像",
|
||||
"Avatar - Tooltip": "向其他人展示的头像",
|
||||
"Back Home": "返回到首页",
|
||||
"Cancel": "取消",
|
||||
"Captcha": "人机验证码",
|
||||
"Cert": "证书",
|
||||
"Cert - Tooltip": "该应用所对应的客户端SDK需要验证的公钥证书",
|
||||
@ -109,6 +114,7 @@
|
||||
"Email": "电子邮箱",
|
||||
"Email - Tooltip": "电子邮件:",
|
||||
"Favicon - Tooltip": "网站的图标",
|
||||
"First name": "名字",
|
||||
"Forget URL": "忘记密码URL",
|
||||
"Forget URL - Tooltip": "忘记密码URL",
|
||||
"Home": "首页",
|
||||
@ -119,6 +125,7 @@
|
||||
"Is enabled - Tooltip": "是否启用",
|
||||
"LDAPs": "LDAP",
|
||||
"LDAPs - Tooltip": "LDAPs",
|
||||
"Last name": "姓氏",
|
||||
"Logo - Tooltip": "应用程序向外展示的图标",
|
||||
"Master password": "万能密码",
|
||||
"Master password - Tooltip": "可用来登录该组织下的所有用户,方便管理员以该用户身份登录,以解决技术问题",
|
||||
@ -137,17 +144,18 @@
|
||||
"Password type - Tooltip": "密码在数据库中存储的形式",
|
||||
"Payments": "付款",
|
||||
"Permissions": "权限",
|
||||
"Personal name": "姓名",
|
||||
"Phone": "手机号",
|
||||
"Phone - Tooltip": "手机号",
|
||||
"Phone prefix": "手机号前缀",
|
||||
"Phone prefix - Tooltip": "移动电话号码前缀,用于区分国家或地区",
|
||||
"Preview": "预览",
|
||||
"Preview - Tooltip": "预览",
|
||||
"Products": "商品",
|
||||
"Provider": "提供商",
|
||||
"Provider - Tooltip": "第三方登录需要配置的提供方",
|
||||
"Providers": "提供商",
|
||||
"Providers - Tooltip": "第三方登录需要配置的提供方",
|
||||
"Real name": "姓名",
|
||||
"Records": "日志",
|
||||
"Request URI": "请求URI",
|
||||
"Resources": "资源",
|
||||
@ -161,11 +169,14 @@
|
||||
"Signup application": "注册应用",
|
||||
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
|
||||
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
|
||||
"State": "状态",
|
||||
"State - Tooltip": "状态",
|
||||
"Swagger": "API文档",
|
||||
"Syncers": "同步器",
|
||||
"Timestamp": "时间戳",
|
||||
"Tokens": "令牌",
|
||||
"URL": "链接",
|
||||
"URL - Tooltip": "URL链接",
|
||||
"Up": "上移",
|
||||
"User": "用户",
|
||||
"User - Tooltip": "用户 - 工具提示",
|
||||
@ -233,6 +244,7 @@
|
||||
"Default avatar": "默认头像",
|
||||
"Edit Organization": "编辑组织",
|
||||
"Favicon": "图标",
|
||||
"New Organization": "添加组织",
|
||||
"Soft deletion": "软删除",
|
||||
"Soft deletion - Tooltip": "启用后,删除用户信息时不会在数据库彻底清除,只会标记为已删除状态",
|
||||
"Website URL": "网页地址",
|
||||
@ -245,7 +257,8 @@
|
||||
"Currency - Tooltip": "如USD(美元),CNY(人民币)等",
|
||||
"Edit Payment": "编辑付款",
|
||||
"Good": "商品",
|
||||
"Good - Tooltip": "购买的商品名称"
|
||||
"Good - Tooltip": "购买的商品名称",
|
||||
"New Payment": "添加付款"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "动作",
|
||||
@ -253,10 +266,42 @@
|
||||
"Edit Permission": "编辑权限",
|
||||
"Effect": "效果",
|
||||
"Effect - Tooltip": "允许还是拒绝",
|
||||
"New Permission": "添加权限",
|
||||
"Resource type": "资源类型",
|
||||
"Resource type - Tooltip": "授权资源的类型",
|
||||
"Resources": "资源"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "支付宝",
|
||||
"Buy Product": "购买商品",
|
||||
"CNY": "人民币",
|
||||
"Currency": "币种",
|
||||
"Currency - Tooltip": "币种 - 工具提示",
|
||||
"Detail": "详情",
|
||||
"Detail - Tooltip": "详情 - 工具提示",
|
||||
"Edit Product": "编辑商品",
|
||||
"Image": "图片",
|
||||
"Image - Tooltip": "图片 - 工具提示",
|
||||
"New Product": "添加商品",
|
||||
"Pay": "支付方式",
|
||||
"Payment providers": "支付提供商",
|
||||
"Payment providers - Tooltip": "支付提供商 - 工具提示",
|
||||
"Paypal": "Paypal",
|
||||
"Price": "价格",
|
||||
"Price - Tooltip": "价格 - 工具提示",
|
||||
"Quantity": "库存",
|
||||
"Quantity - Tooltip": "库存 - 工具提示",
|
||||
"SKU": "货号",
|
||||
"Sold": "售出",
|
||||
"Sold - Tooltip": "售出 - 工具提示",
|
||||
"Tag": "类别",
|
||||
"Tag - Tooltip": "类别 - 工具提示",
|
||||
"Test buy page..": "测试购买页面..",
|
||||
"There is no payment channel for this product.": "该商品没有付款方式。",
|
||||
"This product is currently not in sale.": "该商品目前未在售。",
|
||||
"USD": "美元",
|
||||
"WeChat Pay": "微信支付"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "访问密钥",
|
||||
"Access key - Tooltip": "Access key",
|
||||
@ -299,6 +344,7 @@
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "登录行为,二维码或者静默授权登录",
|
||||
"Name": "名称",
|
||||
"New Provider": "添加提供商",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "解析元数据成功",
|
||||
"Port": "端口",
|
||||
@ -362,6 +408,7 @@
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "编辑角色",
|
||||
"New Role": "添加角色",
|
||||
"Sub roles": "包含角色",
|
||||
"Sub roles - Tooltip": "当前角色所包含的子角色",
|
||||
"Sub users": "包含用户",
|
||||
@ -381,8 +428,10 @@
|
||||
"Please input your address!": "请输入您的地址!",
|
||||
"Please input your affiliation!": "请输入您所在的工作单位!",
|
||||
"Please input your display name!": "请输入您的显示名称!",
|
||||
"Please input your personal name!": "请输入您的姓名!",
|
||||
"Please input your first name!": "请输入您的名字!",
|
||||
"Please input your last name!": "请输入您的姓氏!",
|
||||
"Please input your phone number!": "请输入您的手机号码!",
|
||||
"Please input your real name!": "请输入您的姓名!",
|
||||
"Please select your country/region!": "请选择您的国家/地区",
|
||||
"Terms of Use": "《用户协议》",
|
||||
"The input is not valid Email!": "您输入的电子邮箱格式有误!",
|
||||
@ -410,6 +459,7 @@
|
||||
"Error text": "错误信息",
|
||||
"Error text - Tooltip": "同步器连接数据库时发生的错误",
|
||||
"Is hashed": "是否参与哈希计算",
|
||||
"New Syncer": "添加同步器",
|
||||
"Sync interval": "同步间隔",
|
||||
"Sync interval - Tooltip": "单位为秒",
|
||||
"Table": "表名",
|
||||
@ -424,6 +474,7 @@
|
||||
"Authorization code": "授权码",
|
||||
"Edit Token": "编辑令牌",
|
||||
"Expires in": "有效期",
|
||||
"New Token": "添加令牌",
|
||||
"Scope": "范围",
|
||||
"Token type": "令牌类型"
|
||||
},
|
||||
@ -462,6 +513,7 @@
|
||||
"Modify password...": "编辑密码...",
|
||||
"New Email": "新邮箱",
|
||||
"New Password": "新密码",
|
||||
"New User": "添加用户",
|
||||
"New phone": "新手机号",
|
||||
"OK": "确定",
|
||||
"Old Password": "旧密码",
|
||||
@ -498,6 +550,7 @@
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "HTTP方法",
|
||||
"Name": "名称",
|
||||
"New Webhook": "添加Webhook",
|
||||
"URL": "网址",
|
||||
"URL - Tooltip": "URL",
|
||||
"Value": "值"
|
||||
|
Reference in New Issue
Block a user