Compare commits

...

12 Commits

Author SHA1 Message Date
Yaodong Yu
d12117324c feat: support admin to enable MFA for other users (#2221)
* feat: support admin enable user sms and email mfa

* chore: update ci

* chore: update ci
2023-08-17 17:19:24 +08:00
hsluoyz
1a6c9fbf69 Fix typo in README 2023-08-17 14:47:09 +08:00
hsluoyz
dd60d79af9 Fix typo in README 2023-08-17 14:46:10 +08:00
Yang Luo
73d314c7fe Add MfaTotpPeriodInSeconds param 2023-08-16 21:48:54 +08:00
Yaodong Yu
27959e0f6f fix: fix crash in UserEditPage.js 2023-08-16 15:57:48 +08:00
Baihhh
47f40c5b24 feat: support 3 more UI languages (#2218)
Signed-off-by: baihhh <2542274498@qq.com>
2023-08-16 15:54:34 +08:00
haiwu
2ff9020884 feat: support Stripe payment provider (#2204)
* feat: add stripe payment provider

* feat: support stripe payment

* feat: delete todo comment

* feat: remove description struct

* feat: change outOrderId->orderId
2023-08-15 00:16:30 +08:00
Yang Luo
abaf4ca8d9 Make GetDashboard() faster 2023-08-14 15:43:09 +08:00
8ff0cfd6ec feat: support dashboard in homepage (#2207)
* feat: support dashboard

* feat: support dashboard
2023-08-14 15:31:29 +08:00
Yang Luo
7a2a40edcc Improve table columns 2023-08-14 12:19:02 +08:00
Yang Luo
b7a001ea39 Fix property empty issue 2023-08-14 12:09:50 +08:00
haiwu
891e8e21d8 feat: support Web3-Onboard provider (#2209)
* feat: add Web3-Onboard idp

* feat: update Web3-Onboard logo

* feat: update package.json

* feat: remove unused package

* feat: add yarn build param --max_old_space_size=4096

* feat: remove log

* feat: add Wallet configure

* feat: remove hardware wallets
2023-08-13 23:58:57 +08:00
68 changed files with 7311 additions and 206 deletions

View File

@@ -110,7 +110,7 @@ jobs:
with:
start: yarn start
wait-on: 'http://localhost:7001'
wait-on-timeout: 180
wait-on-timeout: 210
working-directory: ./web
- uses: actions/upload-artifact@v3

View File

@@ -11,7 +11,7 @@
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
@@ -23,16 +23,16 @@
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casbin/casdoor?style=flat-square" alt="license">
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
</a>
<a href="https://github.com/casdoor/casdoor/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casbin/casdoor?style=flat-square">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casbin/casdoor?style=flat-square">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casbin/casdoor?style=flat-square">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
</a>
<a href="https://crowdin.com/project/casdoor-site">
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">

View File

@@ -0,0 +1,33 @@
// Copyright 2021 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 "github.com/casdoor/casdoor/object"
// GetDashboard
// @Title GetDashboard
// @Tag GetDashboard API
// @Description get information of dashboard
// @Success 200 {object} controllers.Response The Response object
// @router /get-dashboard [get]
func (c *ApiController) GetDashboard() {
data, err := object.GetDashboard()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(data)
}

View File

@@ -361,6 +361,9 @@ func (c *ApiController) UploadResource() {
return
}
if user.Properties == nil {
user.Properties = map[string]string{}
}
user.Properties[tag] = fileUrl
user.Properties["isIdCardVerified"] = "false"
_, err = object.UpdateUser(user.GetId(), user, []string{"properties"}, false)

1
go.mod
View File

@@ -51,6 +51,7 @@ require (
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.8.3
github.com/stripe/stripe-go/v74 v74.29.0 // indirect
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
github.com/tklauser/go-sysconf v0.3.10 // indirect

3
go.sum
View File

@@ -1476,6 +1476,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stripe/stripe-go/v74 v74.29.0 h1:ffJ+1Ta1Ccg7yDDz+SfjixX0KizEEJ/wNVRoFYkdwFY=
github.com/stripe/stripe-go/v74 v74.29.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
@@ -1699,6 +1701,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=

View File

@@ -36,6 +36,9 @@ func TestGenerateI18nFrontend(t *testing.T) {
applyToOtherLanguage("frontend", "it", data)
applyToOtherLanguage("frontend", "ms", data)
applyToOtherLanguage("frontend", "tr", data)
applyToOtherLanguage("frontend", "ar", data)
applyToOtherLanguage("frontend", "he", data)
applyToOtherLanguage("frontend", "fi", data)
}
func TestGenerateI18nBackend(t *testing.T) {
@@ -55,4 +58,7 @@ func TestGenerateI18nBackend(t *testing.T) {
applyToOtherLanguage("backend", "it", data)
applyToOtherLanguage("backend", "ms", data)
applyToOtherLanguage("backend", "tr", data)
applyToOtherLanguage("backend", "ar", data)
applyToOtherLanguage("backend", "he", data)
applyToOtherLanguage("backend", "fi", data)
}

142
i18n/locales/ar/data.json Normal file
View File

@@ -0,0 +1,142 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

142
i18n/locales/fi/data.json Normal file
View File

@@ -0,0 +1,142 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

142
i18n/locales/he/data.json Normal file
View File

@@ -0,0 +1,142 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -24,20 +24,10 @@ import (
"golang.org/x/oauth2"
)
const Web3AuthTokenKey = "web3AuthToken"
type MetaMaskIdProvider struct {
Client *http.Client
}
type Web3AuthToken struct {
Address string `json:"address"`
Nonce string `json:"nonce"`
CreateAt uint64 `json:"createAt"`
TypedData string `json:"typedData"`
Signature string `json:"signature"` // signature for typed data
}
func NewMetaMaskIdProvider() *MetaMaskIdProvider {
idp := &MetaMaskIdProvider{}
return idp

View File

@@ -111,6 +111,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
case "MetaMask":
return NewMetaMaskIdProvider()
case "Web3Onboard":
return NewWeb3OnboardIdProvider()
default:
if isGothSupport(idpInfo.Type) {
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)

103
idp/web3onboard.go Normal file
View File

@@ -0,0 +1,103 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package idp
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
"golang.org/x/oauth2"
)
const Web3AuthTokenKey = "web3AuthToken"
type Web3AuthToken struct {
Address string `json:"address"`
Nonce string `json:"nonce"`
CreateAt uint64 `json:"createAt"`
TypedData string `json:"typedData"` // typed data use for application
Signature string `json:"signature"` // signature for typed data
WalletType string `json:"walletType"` // e.g."MetaMask", "Coinbase"
}
type Web3OnboardIdProvider struct {
Client *http.Client
}
func NewWeb3OnboardIdProvider() *Web3OnboardIdProvider {
idp := &Web3OnboardIdProvider{}
return idp
}
func (idp *Web3OnboardIdProvider) SetHttpClient(client *http.Client) {
idp.Client = client
}
func (idp *Web3OnboardIdProvider) GetToken(code string) (*oauth2.Token, error) {
web3AuthToken := Web3AuthToken{}
if err := json.Unmarshal([]byte(code), &web3AuthToken); err != nil {
return nil, err
}
token := &oauth2.Token{
AccessToken: fmt.Sprintf("%v:%v", Web3AuthTokenKey, web3AuthToken.Address),
TokenType: "Bearer",
Expiry: time.Now().AddDate(0, 1, 0),
}
token = token.WithExtra(map[string]interface{}{
Web3AuthTokenKey: web3AuthToken,
})
return token, nil
}
func (idp *Web3OnboardIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
web3AuthToken, ok := token.Extra(Web3AuthTokenKey).(Web3AuthToken)
if !ok {
return nil, errors.New("invalid web3AuthToken")
}
fmtAddress := fmt.Sprintf("%v_%v",
strings.ReplaceAll(strings.TrimSpace(web3AuthToken.WalletType), " ", "_"),
web3AuthToken.Address,
)
userInfo := &UserInfo{
Id: fmtAddress,
Username: fmtAddress,
DisplayName: fmtAddress,
AvatarUrl: fmt.Sprintf("metamask:%v", forceEthereumAddress(web3AuthToken.Address)),
}
return userInfo, nil
}
func forceEthereumAddress(address string) string {
// The required address to general MetaMask avatar is a string of length 42 that represents an Ethereum address.
// This function is used to force any address as an Ethereum address
address = strings.TrimSpace(address)
var builder strings.Builder
for _, ch := range address {
builder.WriteRune(ch)
}
for len(builder.String()) < 42 {
builder.WriteString("0")
}
if len(builder.String()) > 42 {
return builder.String()[:42]
}
return builder.String()
}

View File

@@ -9,11 +9,11 @@
"passwordType": "plain",
"passwordSalt": "",
"passwordOptions": ["AtLeast6"],
"countryCodes": ["US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR"],
"countryCodes": ["US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR", "DZ", "IL", "PH"],
"defaultAvatar": "",
"defaultApplication": "",
"tags": [],
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr"],
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr","ar", "he", "fi"],
"masterPassword": "",
"initScore": 2000,
"enableSoftDeletion": false,

140
object/get-dashboard.go Normal file
View File

@@ -0,0 +1,140 @@
// Copyright 2021 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 (
"sync"
"time"
)
type Dashboard struct {
OrganizationCounts []int `json:"organizationCounts"`
UserCounts []int `json:"userCounts"`
ProviderCounts []int `json:"providerCounts"`
ApplicationCounts []int `json:"applicationCounts"`
SubscriptionCounts []int `json:"subscriptionCounts"`
}
func GetDashboard() (*Dashboard, error) {
dashboard := &Dashboard{
OrganizationCounts: make([]int, 31),
UserCounts: make([]int, 31),
ProviderCounts: make([]int, 31),
ApplicationCounts: make([]int, 31),
SubscriptionCounts: make([]int, 31),
}
var wg sync.WaitGroup
organizations := []Organization{}
users := []User{}
providers := []Provider{}
applications := []Application{}
subscriptions := []Subscription{}
wg.Add(5)
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&organizations); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&users); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&providers); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&applications); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&subscriptions); err != nil {
panic(err)
}
}()
wg.Wait()
nowTime := time.Now()
for i := 30; i >= 0; i-- {
cutTime := nowTime.AddDate(0, 0, -i)
dashboard.OrganizationCounts[30-i] = countCreatedBefore(organizations, cutTime)
dashboard.UserCounts[30-i] = countCreatedBefore(users, cutTime)
dashboard.ProviderCounts[30-i] = countCreatedBefore(providers, cutTime)
dashboard.ApplicationCounts[30-i] = countCreatedBefore(applications, cutTime)
dashboard.SubscriptionCounts[30-i] = countCreatedBefore(subscriptions, cutTime)
}
return dashboard, nil
}
func countCreatedBefore(objects interface{}, before time.Time) int {
count := 0
switch obj := objects.(type) {
case []Organization:
for _, o := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", o.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []User:
for _, u := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", u.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Provider:
for _, p := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", p.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Application:
for _, a := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", a.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Subscription:
for _, s := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", s.CreatedTime)
if createdTime.Before(before) {
count++
}
}
}
return count
}

View File

@@ -17,6 +17,7 @@ package object
import (
"errors"
"fmt"
"time"
"github.com/beego/beego"
"github.com/beego/beego/context"
@@ -25,7 +26,10 @@ import (
"github.com/pquerna/otp/totp"
)
const MfaTotpSecretSession = "mfa_totp_secret"
const (
MfaTotpSecretSession = "mfa_totp_secret"
MfaTotpPeriodInSeconds = 30
)
type TotpMfa struct {
Config *MfaProps
@@ -76,7 +80,13 @@ func (mfa *TotpMfa) SetupVerify(ctx *context.Context, passcode string) error {
if secret == nil {
return errors.New("totp secret is missing")
}
result := totp.Validate(passcode, secret.(string))
result, _ := totp.ValidateCustom(passcode, secret.(string), time.Now().UTC(), totp.ValidateOpts{
Period: MfaTotpPeriodInSeconds,
Skew: 1,
Digits: otp.DigitsSix,
Algorithm: otp.AlgorithmSHA1,
})
if result {
return nil
@@ -133,7 +143,7 @@ func NewTotpMfaUtil(config *MfaProps) *TotpMfa {
return &TotpMfa{
Config: config,
period: 30,
period: MfaTotpPeriodInSeconds,
secretSize: 20,
digits: otp.DigitsSix,
}

View File

@@ -309,8 +309,7 @@ func GetAllRoles(userId string) []string {
func GetBuiltInModel(modelText string) (model.Model, error) {
if modelText == "" {
modelText = `
[request_definition]
modelText = `[request_definition]
r = sub, obj, act
[policy_definition]

View File

@@ -36,7 +36,7 @@ type Provider struct {
Type string `xorm:"varchar(100)" json:"type"`
SubType string `xorm:"varchar(100)" json:"subType"`
Method string `xorm:"varchar(100)" json:"method"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientId string `xorm:"varchar(200)" json:"clientId"`
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`

View File

@@ -170,6 +170,7 @@ type User struct {
Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
MetaMask string `xorm:"metamask varchar(100)" json:"metamask"`
Web3Onboard string `xorm:"web3onboard varchar(100)" json:"web3onboard"`
Custom string `xorm:"custom varchar(100)" json:"custom"`
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`

View File

@@ -90,7 +90,7 @@ func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, auth
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
OrderId: orderId,
PaymentStatus: PaymentStatePaid,
Price: price,
PaymentName: paymentName,

View File

@@ -255,7 +255,7 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
OrderId: orderId,
Price: price,
PaymentStatus: PaymentStatePaid,
PaymentName: paymentName,

View File

@@ -52,13 +52,12 @@ func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentPro
func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
// https://github.com/go-pay/gopay/blob/main/doc/paypal.md
priceStr := strconv.FormatFloat(price, 'f', 2, 64)
units := make([]*paypal.PurchaseUnit, 0, 1)
unit := &paypal.PurchaseUnit{
ReferenceId: util.GetRandomString(16),
Amount: &paypal.Amount{
CurrencyCode: currency, // e.g."USD"
Value: priceStr, // e.g."100.00"
CurrencyCode: currency, // e.g."USD"
Value: priceFloat64ToString(price), // e.g."100.00"
},
Description: joinAttachString([]string{productDisplayName, productName, providerName}),
}
@@ -147,16 +146,15 @@ func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, auth
paymentStatus = PaymentStateError
}
notifyResult = &NotifyResult{
PaymentStatus: paymentStatus,
PaymentName: paymentName,
PaymentStatus: paymentStatus,
PaymentName: paymentName,
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
Price: price,
Currency: currency,
OutOrderId: orderId,
OrderId: orderId,
}
return notifyResult, nil
}

View File

@@ -24,6 +24,7 @@ const (
PaymentStatePaid PaymentState = "Paid"
PaymentStateCreated PaymentState = "Created"
PaymentStateCanceled PaymentState = "Canceled"
PaymentStateTimeout PaymentState = "Timeout"
PaymentStateError PaymentState = "Error"
)
@@ -32,13 +33,13 @@ type NotifyResult struct {
PaymentStatus PaymentState
NotifyMessage string
ProviderName string
ProductName string
ProductDisplayName string
ProviderName string
Price float64
Currency string
OutOrderId string
OrderId string
}
type PaymentProvider interface {
@@ -75,6 +76,12 @@ func GetPaymentProvider(typ string, clientId string, clientSecret string, host s
return nil, err
}
return pp, nil
} else if typ == "Stripe" {
pp, err := NewStripePaymentProvider(clientId, clientSecret)
if err != nil {
return nil, err
}
return pp, nil
}
return nil, nil

166
pp/stripe.go Normal file
View File

@@ -0,0 +1,166 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pp
import (
"fmt"
"net/http"
"time"
"github.com/casdoor/casdoor/conf"
"github.com/stripe/stripe-go/v74"
stripeCheckout "github.com/stripe/stripe-go/v74/checkout/session"
stripeIntent "github.com/stripe/stripe-go/v74/paymentintent"
stripePrice "github.com/stripe/stripe-go/v74/price"
stripeProduct "github.com/stripe/stripe-go/v74/product"
)
type StripePaymentProvider struct {
PublishableKey string
SecretKey string
isProd bool
}
func NewStripePaymentProvider(PublishableKey, SecretKey string) (*StripePaymentProvider, error) {
isProd := false
if conf.GetConfigString("runmode") == "prod" {
isProd = true
}
pp := &StripePaymentProvider{
PublishableKey: PublishableKey,
SecretKey: SecretKey,
isProd: isProd,
}
stripe.Key = pp.SecretKey
return pp, nil
}
func (pp *StripePaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (payUrl string, orderId string, err error) {
// Create a temp product
description := joinAttachString([]string{productName, productDisplayName, providerName})
productParams := &stripe.ProductParams{
Name: stripe.String(productDisplayName),
Description: stripe.String(description),
DefaultPriceData: &stripe.ProductDefaultPriceDataParams{
UnitAmount: stripe.Int64(priceFloat64ToInt64(price)),
Currency: stripe.String(currency),
},
}
sProduct, err := stripeProduct.New(productParams)
if err != nil {
return "", "", err
}
// Create a price for an existing product
priceParams := &stripe.PriceParams{
Currency: stripe.String(currency),
UnitAmount: stripe.Int64(priceFloat64ToInt64(price)),
Product: stripe.String(sProduct.ID),
}
sPrice, err := stripePrice.New(priceParams)
if err != nil {
return "", "", err
}
// Create a Checkout Session
checkoutParams := &stripe.CheckoutSessionParams{
LineItems: []*stripe.CheckoutSessionLineItemParams{
{
Price: stripe.String(sPrice.ID),
Quantity: stripe.Int64(1),
},
},
Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),
SuccessURL: stripe.String(returnUrl),
CancelURL: stripe.String(returnUrl),
ClientReferenceID: stripe.String(paymentName),
ExpiresAt: stripe.Int64(time.Now().Add(30 * time.Minute).Unix()),
}
checkoutParams.AddMetadata("product_description", description)
sCheckout, err := stripeCheckout.New(checkoutParams)
if err != nil {
return "", "", err
}
return sCheckout.URL, sCheckout.ID, nil
}
func (pp *StripePaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
notifyResult := &NotifyResult{}
sCheckout, err := stripeCheckout.Get(orderId, nil)
if err != nil {
return nil, err
}
switch sCheckout.Status {
case "open":
// The checkout session is still in progress. Payment processing has not started
notifyResult.PaymentStatus = PaymentStateCreated
return notifyResult, nil
case "complete":
// The checkout session is complete. Payment processing may still be in progress
case "expired":
// The checkout session has expired. No further processing will occur
notifyResult.PaymentStatus = PaymentStateTimeout
return notifyResult, nil
default:
notifyResult.PaymentStatus = PaymentStateError
notifyResult.NotifyMessage = fmt.Sprintf("unexpected stripe checkout status: %v", sCheckout.Status)
return notifyResult, nil
}
switch sCheckout.PaymentStatus {
case "paid":
// Skip
case "unpaid":
notifyResult.PaymentStatus = PaymentStateCreated
return notifyResult, nil
default:
notifyResult.PaymentStatus = PaymentStateError
notifyResult.NotifyMessage = fmt.Sprintf("unexpected stripe checkout payment status: %v", sCheckout.PaymentStatus)
return notifyResult, nil
}
// Once payment is successful, the Checkout Session will contain a reference to the successful `PaymentIntent`
sIntent, err := stripeIntent.Get(sCheckout.PaymentIntent.ID, nil)
var (
productName string
productDisplayName string
providerName string
)
if description, ok := sCheckout.Metadata["product_description"]; ok {
productName, productDisplayName, providerName, _ = parseAttachString(description)
}
notifyResult = &NotifyResult{
PaymentName: sCheckout.ClientReferenceID,
PaymentStatus: PaymentStatePaid,
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
Price: priceInt64ToFloat64(sIntent.Amount),
Currency: string(sIntent.Currency),
OrderId: orderId,
}
return notifyResult, nil
}
func (pp *StripePaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
return "", nil
}
func (pp *StripePaymentProvider) GetResponseError(err error) string {
if err == nil {
return "success"
} else {
return "fail"
}
}

View File

@@ -16,6 +16,8 @@ package pp
import (
"fmt"
"math"
"strconv"
"strings"
)
@@ -35,3 +37,15 @@ func parseAttachString(s string) (string, string, string, error) {
}
return tokens[0], tokens[1], tokens[2], nil
}
func priceInt64ToFloat64(price int64) float64 {
return float64(price) / 100
}
func priceFloat64ToInt64(price float64) int64 {
return int64(math.Round(price * 100))
}
func priceFloat64ToString(price float64) string {
return strconv.FormatFloat(price, 'f', 2, 64)
}

View File

@@ -113,7 +113,7 @@ func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, auth
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
OrderId: orderId,
Price: price,
PaymentStatus: PaymentStatePaid,
PaymentName: paymentName,

View File

@@ -51,6 +51,7 @@ func initAPI() {
beego.Router("/api/signup", &controllers.ApiController{}, "POST:Signup")
beego.Router("/api/login", &controllers.ApiController{}, "POST:Login")
beego.Router("/api/get-app-login", &controllers.ApiController{}, "GET:GetApplicationLogin")
beego.Router("/api/get-dashboard", &controllers.ApiController{}, "GET:GetDashboard")
beego.Router("/api/logout", &controllers.ApiController{}, "GET,POST:Logout")
beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount")
beego.Router("/api/userinfo", &controllers.ApiController{}, "GET:GetUserinfo")

View File

@@ -51,31 +51,46 @@ module.exports = {
},
],
webpack: {
// use polyfill Buffer with Webpack 5
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
// https://craco.js.org/docs/configuration/webpack/
configure: (webpackConfig, { env, paths }) => {
webpackConfig.resolve.fallback = {
// "process": require.resolve('process/browser'),
// "util": require.resolve("util/"),
// "url": require.resolve("url/"),
// "zlib": require.resolve("browserify-zlib"),
// "stream": require.resolve("stream-browserify"),
// "http": require.resolve("stream-http"),
// "https": require.resolve("https-browserify"),
// "assert": require.resolve("assert/"),
"buffer": require.resolve('buffer/'),
"process": false,
"util": false,
"url": false,
"zlib": false,
"stream": false,
"http": false,
"https": false,
"assert": false,
"buffer": false,
};
return webpackConfig;
configure: {
// ignore webpack warnings by source-map-loader
// https://github.com/facebook/create-react-app/pull/11752#issuecomment-1345231546
ignoreWarnings: [
function ignoreSourcemapsloaderWarnings(warning) {
return (
warning.module &&
warning.module.resource.includes('node_modules') &&
warning.details &&
warning.details.includes('source-map-loader')
)
},
],
// use polyfill Buffer with Webpack 5
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
// https://craco.js.org/docs/configuration/webpack/
resolve: {
fallback: {
// "process": require.resolve('process/browser'),
// "util": require.resolve("util/"),
// "url": require.resolve("url/"),
// "zlib": require.resolve("browserify-zlib"),
// "stream": require.resolve("stream-browserify"),
// "http": require.resolve("stream-http"),
// "https": require.resolve("https-browserify"),
// "assert": require.resolve("assert/"),
"buffer": require.resolve('buffer/'),
"process": false,
"util": false,
"url": false,
"zlib": false,
"stream": false,
"http": false,
"https": false,
"assert": false,
"buffer": false,
"crypto": false,
"os": false,
},
}
},
}
};

View File

@@ -13,6 +13,16 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@web3-onboard/coinbase": "^2.2.5",
"@web3-onboard/core": "^2.20.5",
"@web3-onboard/frontier": "^2.0.4",
"@web3-onboard/gnosis": "^2.1.10",
"@web3-onboard/infinity-wallet": "^2.0.4",
"@web3-onboard/injected-wallets": "^2.10.4",
"@web3-onboard/react": "^2.8.10",
"@web3-onboard/sequence": "^2.0.8",
"@web3-onboard/taho": "^2.0.5",
"@web3-onboard/trust": "^2.0.4",
"antd": "5.2.3",
"antd-token-previewer": "^1.1.0-22",
"buffer": "^6.0.3",
@@ -20,7 +30,9 @@
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.25.0",
"craco-less": "^2.0.0",
"echarts": "^5.4.3",
"eslint-plugin-unused-imports": "^2.0.0",
"ethers": "5.6.9",
"file-saver": "^2.0.5",
"i18n-iso-countries": "^7.0.0",
"i18next": "^19.8.9",
@@ -44,7 +56,7 @@
},
"scripts": {
"start": "cross-env PORT=7001 craco start",
"build": "craco build",
"build": "craco --max_old_space_size=4096 build",
"test": "craco test",
"eject": "craco eject",
"crowdin:sync": "crowdin upload && crowdin download",

View File

@@ -351,7 +351,7 @@ class App extends Component {
}
&nbsp;
&nbsp;
{Setting.isMobile() ? null : Setting.getNameAtLeast(this.state.account.displayName)} &nbsp; <DownOutlined />
{Setting.isMobile() ? null : Setting.getShortText(Setting.getNameAtLeast(this.state.account.displayName), 30)} &nbsp; <DownOutlined />
&nbsp;
&nbsp;
&nbsp;

View File

@@ -169,7 +169,7 @@ class EnforcerEditPage extends React.Component {
<Select virtual={false} disabled={Setting.builtInObject(this.state.enforcer)} style={{width: "100%"}} value={this.state.enforcer.model} onChange={(model => {
this.updateEnforcerField("model", model);
})}
options={this.state.models.map((model) => Setting.getOption(model.displayName, `${model.owner}/${model.name}`))
options={this.state.models.map((model) => Setting.getOption(`${model.owner}/${model.name}`, `${model.owner}/${model.name}`))
} />
</Col>
</Row>
@@ -181,7 +181,7 @@ class EnforcerEditPage extends React.Component {
<Select virtual={false} disabled={Setting.builtInObject(this.state.enforcer)} style={{width: "100%"}} value={this.state.enforcer.adapter} onChange={(adapter => {
this.updateEnforcerField("adapter", adapter);
})}
options={this.state.adapters.map((adapter) => Setting.getOption(adapter.name, `${adapter.owner}/${adapter.name}`))
options={this.state.adapters.map((adapter) => Setting.getOption(`${adapter.owner}/${adapter.name}`, `${adapter.owner}/${adapter.name}`))
} />
</Col>
</Row>

View File

@@ -75,7 +75,7 @@ class EnforcerListPage extends BaseListPage {
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "150px",
width: "200px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
@@ -116,10 +116,42 @@ class EnforcerListPage extends BaseListPage {
title: i18next.t("general:Display name"),
dataIndex: "displayName",
key: "displayName",
width: "200px",
// width: "200px",
sorter: true,
...this.getColumnSearchProps("displayName"),
},
{
title: i18next.t("general:Model"),
dataIndex: "model",
key: "model",
width: "250px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
render: (text, record, index) => {
return (
<Link to={`/models/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Adapter"),
dataIndex: "adapter",
key: "adapter",
width: "250px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
render: (text, record, index) => {
return (
<Link to={`/adapters/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Is enabled"),
dataIndex: "isEnabled",
@@ -136,7 +168,7 @@ class EnforcerListPage extends BaseListPage {
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "170px",
width: "180px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (

View File

@@ -103,7 +103,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "120px",
width: "150px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
@@ -119,7 +119,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
width: "140px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
@@ -134,7 +134,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "150px",
width: "180px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
@@ -144,7 +144,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Updated time"),
dataIndex: "updatedTime",
key: "updatedTime",
width: "150px",
width: "180px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
@@ -154,7 +154,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Display name"),
dataIndex: "displayName",
key: "displayName",
width: "100px",
// width: "200px",
sorter: true,
...this.getColumnSearchProps("displayName"),
},
@@ -162,7 +162,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Type"),
dataIndex: "type",
key: "type",
width: "110px",
width: "140px",
sorter: true,
filterMultiple: false,
filters: [
@@ -177,7 +177,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("group:Parent group"),
dataIndex: "parentId",
key: "parentId",
width: "110px",
width: "220px",
sorter: true,
...this.getColumnSearchProps("parentId"),
render: (text, record, index) => {
@@ -199,7 +199,7 @@ class GroupListPage extends BaseListPage {
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "170px",
width: "180px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
const haveChildren = this.state.groups.find((group) => group.parentId === record.id) !== undefined;

View File

@@ -182,7 +182,7 @@ class OrganizationListPage extends BaseListPage {
title: i18next.t("organization:Website URL"),
dataIndex: "websiteUrl",
key: "websiteUrl",
width: "300px",
width: "200px",
sorter: true,
...this.getColumnSearchProps("websiteUrl"),
render: (text, record, index) => {
@@ -243,7 +243,7 @@ class OrganizationListPage extends BaseListPage {
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "320px",
width: "350px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (

View File

@@ -48,7 +48,7 @@ class PaymentResultPage extends React.Component {
});
// window.console.log("payment=", res.data);
if (res.data.state === "Created") {
if (res.data.type === "PayPal") {
if (["PayPal", "Stripe"].includes(res.data.type)) {
this.setState({
timeout: setTimeout(() => {
PaymentBackend.notifyPayment(this.state.organizationName, this.state.paymentName)
@@ -135,6 +135,26 @@ class PaymentResultPage extends React.Component {
/>
</div>
);
} else if (payment.state === "Timeout") {
return (
<div>
{
Setting.renderHelmet(payment)
}
<Result
status="warning"
title={`${i18next.t("payment:The payment has time out")}: ${payment.productDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
extra={[
<Button type="primary" key="returnUrl" onClick={() => {
this.goToPaymentUrl(payment);
}}>
{i18next.t("payment:Return to Website")}
</Button>,
]}
/>
</div>
);
} else {
return (
<div>

View File

@@ -163,6 +163,8 @@ class ProductBuyPage extends React.Component {
text = i18next.t("product:WeChat Pay");
} else if (provider.type === "PayPal") {
text = i18next.t("product:PayPal");
} else if (provider.type === "Stripe") {
text = i18next.t("product:Stripe");
}
return (

View File

@@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
import {Button, Card, Checkbox, Col, Input, InputNumber, Row, Select, Switch} from "antd";
import {LinkOutlined} from "@ant-design/icons";
import * as ProviderBackend from "./backend/ProviderBackend";
import * as Setting from "./Setting";
@@ -25,6 +25,7 @@ import copy from "copy-to-clipboard";
import {CaptchaPreview} from "./common/CaptchaPreview";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
import * as Web3Auth from "./auth/Web3Auth";
const {Option} = Select;
const {TextArea} = Input;
@@ -1011,6 +1012,30 @@ class ProviderEditPage extends React.Component {
</Row>
) : null
}
{
this.state.provider.type === "Web3Onboard" ? (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Wallets"), i18next.t("provider:Wallets - Tooltip"))} :
</Col>
<Col span={22}>
<Checkbox.Group
options={Web3Auth.getWeb3OnboardWalletsOptions()}
value={() => {
try {
return JSON.parse(this.state.provider.metadata);
} catch {
return ["injected"];
}
}}
onChange={options => {
this.updateProviderField("metadata", JSON.stringify(options));
}}
/>
</Col>
</Row>
) : null
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Provider URL"), i18next.t("provider:Provider URL - Tooltip"))} :

View File

@@ -46,6 +46,9 @@ export const Countries = [{label: "English", key: "en", country: "US", alt: "Eng
{label: "Itariano", key: "it", country: "IT", alt: "Itariano"},
{label: "Marley", key: "ms", country: "MY", alt: "Marley"},
{label: "Tkiš", key: "tr", country: "TR", alt: "Tkiš"},
{label: "لغة عربية", key: "ar", country: "DZ", alt: "لغة عربية"},
{label: "עִבְרִית", key: "he", country: "IL", alt: "עִבְרִית"},
{label: "Filipino", key: "fi", country: "PH", alt: "Filipino"},
];
export function getThemeData(organization, application) {
@@ -217,6 +220,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/payment_paypal.png`,
url: "https://www.paypal.com/",
},
"Stripe": {
logo: `${StaticBaseUrl}/img/social_stripe.png`,
url: "https://stripe.com/",
},
"GC": {
logo: `${StaticBaseUrl}/img/payment_gc.png`,
url: "https://gc.org",
@@ -259,6 +266,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_metamask.svg`,
url: "https://metamask.io/",
},
"Web3Onboard": {
logo: `${StaticBaseUrl}/img/social_web3onboard.svg`,
url: "https://onboard.blocknative.com/",
},
},
};
@@ -929,6 +940,7 @@ export function getProviderTypeOptions(category) {
{id: "Alipay", name: "Alipay"},
{id: "WeChat Pay", name: "WeChat Pay"},
{id: "PayPal", name: "PayPal"},
{id: "Stripe", name: "Stripe"},
{id: "GC", name: "GC"},
]);
} else if (category === "Captcha") {
@@ -943,6 +955,7 @@ export function getProviderTypeOptions(category) {
} else if (category === "Web3") {
return ([
{id: "MetaMask", name: "MetaMask"},
{id: "Web3Onboard", name: "Web3-Onboard"},
]);
} else {
return [];

View File

@@ -15,9 +15,11 @@
import React from "react";
import {Button, Card, Col, Input, InputNumber, List, Result, Row, Select, Space, Spin, Switch, Tag} from "antd";
import {withRouter} from "react-router-dom";
import {TotpMfaType} from "./auth/MfaSetupPage";
import * as GroupBackend from "./backend/GroupBackend";
import * as UserBackend from "./backend/UserBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import EnableMfaModal from "./common/modal/EnableMfaModal";
import * as Setting from "./Setting";
import i18next from "i18next";
import CropperDivModal from "./common/modal/CropperDivModal.js";
@@ -138,6 +140,10 @@ class UserEditPage extends React.Component {
}
getUserOrganization() {
if (this.state.user === null || this.state.organizations.length === 0) {
return null;
}
return this.state.organizations.filter(organization => organization.name === this.state.user.owner)[0];
}
@@ -206,23 +212,6 @@ class UserEditPage extends React.Component {
return this.props.account.countryCode;
}
loadMore = (table, type) => {
return <div
style={{
textAlign: "center",
marginTop: 12,
height: 32,
lineHeight: "32px",
}}
>
<Button onClick={() => {
this.setState({
multiFactorAuths: Setting.addRow(table, {"type": type}),
});
}}>{i18next.t("general:Add")}</Button>
</div>;
};
deleteMfa = () => {
this.setState({
RemoveMfaLoading: true,
@@ -570,7 +559,7 @@ class UserEditPage extends React.Component {
{name: "ID card back", value: "idCardBack"},
{name: "ID card with person", value: "idCardWithPerson"},
].map((entry) => {
return this.renderImage(this.state.user.properties[entry.value] || "", this.getIdCardType(entry.name), this.getIdCardText(entry.name), entry.value, disabled);
return this.renderImage(this.state.user.properties === null ? "" : (this.state.user.properties[entry.value] || ""), this.getIdCardType(entry.name), this.getIdCardText(entry.name), entry.value, disabled);
})
}
</Row>
@@ -947,11 +936,18 @@ class UserEditPage extends React.Component {
</Button>
}
</Space>
) : <Button type={"default"} onClick={() => {
this.props.history.push(`/mfa/setup?mfaType=${item.mfaType}`);
}}>
{i18next.t("mfa:Setup")}
</Button>}
) :
<Space>
{item.mfaType !== TotpMfaType && Setting.isAdminUser(this.props.account) && window.location.href.indexOf("/users") !== -1 ?
<EnableMfaModal user={this.state.user} mfaType={item.mfaType} onSuccess={() => {
this.getUser();
}} /> : null}
<Button type={"default"} onClick={() => {
this.props.history.push(`/mfa/setup?mfaType=${item.mfaType}`);
}}>
{i18next.t("mfa:Setup")}
</Button>
</Space>}
</List.Item>
)}
/>
@@ -995,11 +991,13 @@ class UserEditPage extends React.Component {
<Col span={4} style={{textAlign: "center", margin: "auto"}} key={tag}>
{
imgUrl ?
<a target="_blank" rel="noreferrer" href={imgUrl} style={{marginBottom: "10px"}}>
<AccountAvatar src={imgUrl} alt={imgUrl} size={90} style={{marginBottom: "20px"}} />
</a>
<div style={{marginBottom: "10px"}}>
<a target="_blank" rel="noreferrer" href={imgUrl} style={{marginBottom: "10px"}}>
<AccountAvatar src={imgUrl} alt={imgUrl} height={150} />
</a>
</div>
:
<Col style={{height: "78%", border: "1px dotted grey", borderRadius: 3, marginBottom: 5}}>
<Col style={{height: "78%", border: "1px dotted grey", borderRadius: 3, marginBottom: "10px"}}>
<div style={{fontSize: 30, margin: 10}}>+</div>
<div style={{verticalAlign: "middle", marginBottom: 10}}>{`Upload ${title}...`}</div>
</Col>

View File

@@ -17,7 +17,7 @@ import {MetaMaskAvatar} from "react-metamask-avatar";
class AccountAvatar extends React.Component {
render() {
const {src, size} = this.props;
const {src, size, width, height} = this.props;
// The avatar for Metamask account is directly generated by an algorithm based on the address
// src = "metamask:0xC304b2cC0Be8E9ce10fF3Afd34820Ed306A23600";
const matchMetaMask = src.match(/^metamask:(\w+)$/);
@@ -27,9 +27,19 @@ class AccountAvatar extends React.Component {
<MetaMaskAvatar address={address} size={size} />
);
}
return (
<img width={size} height={size} src={src} />
);
if (size !== undefined) {
return (
<img width={size} height={size} src={src} />
);
} else if (width === undefined) {
return (
<img height={height} src={src} />
);
} else if (height === undefined) {
return (
<img width={width} src={src} />
);
}
}
}

View File

@@ -95,7 +95,7 @@ class AuthCallback extends React.Component {
if (code === null) {
code = params.get("authCode");
}
// The code for Metamask is the JSON-serialized string of Web3AuthToken
// The code for Web3 is the JSON-serialized string of Web3AuthToken
// Due to the limited length of URLs, we only pass the web3AuthTokenKey
if (code === null) {
code = params.get("web3AuthTokenKey");

View File

@@ -321,6 +321,10 @@ const authInfo = {
scope: "",
endpoint: "",
},
Web3Onboard: {
scope: "",
endpoint: "",
},
};
export function getProviderUrl(provider) {
@@ -465,5 +469,7 @@ export function getAuthUrl(application, provider, method) {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
} else if (provider.type === "MetaMask") {
return `${redirectUri}?state=${state}`;
} else if (provider.type === "Web3Onboard") {
return `${redirectUri}?state=${state}`;
}
}

View File

@@ -17,7 +17,7 @@ import i18next from "i18next";
import * as Provider from "./Provider";
import {getProviderLogoURL} from "../Setting";
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
import {authViaMetaMask} from "./Web3Auth";
import {authViaMetaMask, authViaWeb3Onboard} from "./Web3Auth";
import QqLoginButton from "./QqLoginButton";
import FacebookLoginButton from "./FacebookLoginButton";
import WeiboLoginButton from "./WeiboLoginButton";
@@ -121,6 +121,8 @@ function goToSamlUrl(provider, location) {
export function goToWeb3Url(application, provider, method) {
if (provider.type === "MetaMask") {
authViaMetaMask(application, provider, method);
} else if (provider.type === "Web3Onboard") {
authViaWeb3Onboard(application, provider, method);
}
}

View File

@@ -18,7 +18,25 @@ import {v4 as uuidv4} from "uuid";
import {SignTypedDataVersion, recoverTypedSignature} from "@metamask/eth-sig-util";
import {getAuthUrl} from "./Provider";
import {Buffer} from "buffer";
// import {toChecksumAddress} from "ethereumjs-util";
import Onboard from "@web3-onboard/core";
import injectedModule from "@web3-onboard/injected-wallets";
import infinityWalletModule from "@web3-onboard/infinity-wallet";
import sequenceModule from "@web3-onboard/sequence";
import trustModule from "@web3-onboard/trust";
import frontierModule from "@web3-onboard/frontier";
import tahoModule from "@web3-onboard/taho";
import coinbaseModule from "@web3-onboard/coinbase";
import gnosisModule from "@web3-onboard/gnosis";
// import keystoneModule from "@web3-onboard/keystone";
// import keepkeyModule from "@web3-onboard/keepkey";
// import dcentModule from "@web3-onboard/dcent";
// import ledgerModule from "@web3-onboard/ledger";
// import trezorModule from "@web3-onboard/trezor";
// import walletConnectModule from "@web3-onboard/walletconnect";
// import fortmaticModule from "@web3-onboard/fortmatic";
// import portisModule from "@web3-onboard/portis";
// import magicModule from "@web3-onboard/magic";
global.Buffer = Buffer;
export function generateNonce() {
@@ -147,3 +165,174 @@ export async function authViaMetaMask(application, provider, method) {
showMessage("error", `${i18next.t("login:Failed to obtain MetaMask authorization")}: ${err.message}`);
}
}
const web3Wallets = {
// injected wallets
injected: {
label: "Injected",
wallet: injectedModule(),
},
// sdk wallets
coinbase: {
label: "Coinbase",
wallet: coinbaseModule(),
},
trust: {
label: "Trust",
wallet: trustModule(),
},
gnosis: {
label: "Gnosis",
wallet: gnosisModule(),
},
sequence: {
label: "Sequence",
wallet: sequenceModule(),
},
taho: {
label: "Taho",
wallet: tahoModule(),
},
frontier: {
label: "Frontier",
wallet: frontierModule(),
},
infinityWallet: {
label: "Infinity Wallet",
wallet: infinityWalletModule(),
},
// hardware wallets
// keystone: {
// label: "Keystone",
// wallet: keystoneModule(),
// },
// keepkey: {
// label: "KeepKey",
// wallet: keepkeyModule(),
// },
// dcent: {
// label: "D'CENT",
// wallet: dcentModule(),
// },
// some wallet need custome `apiKey` or `projectId` configure item
// const magic = magicModule({
// apiKey: "magicApiKey",
// });
// const fortmatic = fortmaticModule({
// apiKey: "fortmaticApiKey",
// });
// const portis = portisModule({
// apiKey: "portisApiKey",
// });
// const ledger = ledgerModule({
// projectId: "ledgerProjectId"
// });
// const walletConnect = walletConnectModule({
// projectId: "walletConnectProjectId",
// });
};
export function getWeb3OnboardWalletsOptions() {
return Object.entries(web3Wallets).map(([key, value]) => ({
label: value.label,
value: key,
}));
}
function getWeb3OnboardWallets(options) {
if (options === null || options === undefined || !Array.isArray(options)) {
return [];
}
return options.map(walletType => {
if (walletType && web3Wallets[walletType]?.wallet) {
return web3Wallets[walletType]?.wallet;
}
});
}
export function initWeb3Onboard(application, provider) {
// init wallet
// options = ["injected","coinbase",...]
const options = JSON.parse(provider.metadata);
const wallets = getWeb3OnboardWallets(options);
// init chain
// const InfuraKey = "2fa45cbe531e4e65be4fcbf408e651a8";
const chains = [
// {
// id: "0x1",
// token: "ETH",
// label: "Ethereum Mainnet",
// rpcUrl: `https://mainnet.infura.io/v3/${InfuraKey}`,
// },
// {
// id: "0x5",
// token: "ETH",
// label: "Goerli",
// rpcUrl: `https://goerli.infura.io/v3/${InfuraKey}`,
// },
{
id: "0x13881",
token: "MATIC",
label: "Polygon - Mumbai",
rpcUrl: "https://matic-mumbai.chainstacklabs.com",
},
{
id: "0x38",
token: "BNB",
label: "Binance",
rpcUrl: "https://bsc-dataseed.binance.org/",
},
{
id: "0xA",
token: "OETH",
label: "Optimism",
rpcUrl: "https://mainnet.optimism.io",
},
{
id: "0xA4B1",
token: "ARB-ETH",
label: "Arbitrum",
rpcUrl: "https://rpc.ankr.com/arbitrum",
},
];
const appMetadata = {
name: "Casdoor",
description: "Connect a wallet using Casdoor",
recommendedInjectedWallets: [
{name: "MetaMask", url: "https://metamask.io"},
{name: "Coinbase", url: "https://wallet.coinbase.com/"},
],
};
const web3Onboard = Onboard({
wallets,
chains,
appMetadata,
});
return web3Onboard;
}
export async function authViaWeb3Onboard(application, provider, method) {
try {
const onboard = initWeb3Onboard(application, provider);
const connectedWallets = await onboard.connectWallet();
if (connectedWallets.length > 0) {
const wallet = connectedWallets[0];
const account = wallet.accounts[0];
const address = account.address;
const token = {
address: address, // e.g."0xbd5444d31fe4139ee36bea29e43d4ac67ae276de"
walletType: wallet.label, // e.g."MetaMask"
createAt: Math.floor(new Date().getTime() / 1000),
};
setWeb3AuthToken(token);
const redirectUri = `${getAuthUrl(application, provider, method)}&web3AuthTokenKey=${getWeb3AuthTokenKey(address)}`;
goToLink(redirectUri);
}
} catch (err) {
showMessage("error", `${i18next.t("login:Failed to obtain Web3-Onboard authorization")}: ${err}`);
}
}

View File

@@ -0,0 +1,25 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "../Setting";
export function getDashboard(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-dashboard`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}

View File

@@ -13,8 +13,11 @@
// limitations under the License.
import React from "react";
import {Card, Col, Row} from "antd";
import {Card, Col, Row, Spin, Statistic} from "antd";
import {ArrowUpOutlined} from "@ant-design/icons";
import * as ApplicationBackend from "../backend/ApplicationBackend";
import * as DashboardBackend from "../backend/DashboardBackend";
import * as echarts from "echarts";
import * as Setting from "../Setting";
import SingleCard from "./SingleCard";
import i18next from "i18next";
@@ -25,11 +28,13 @@ class HomePage extends React.Component {
this.state = {
classes: props,
applications: null,
dashboardData: null,
};
}
UNSAFE_componentWillMount() {
this.getApplicationsByOrganization(this.props.account.owner);
this.getDashboard();
}
getApplicationsByOrganization(organizationName) {
@@ -41,6 +46,21 @@ class HomePage extends React.Component {
});
}
getDashboard() {
DashboardBackend.getDashboard()
.then((res) => {
if (res.status === "ok") {
this.setState({
dashboardData: res.data,
}, () => {
this.renderEChart();
});
} else {
Setting.showMessage("error", res.msg);
}
});
}
getItems() {
let items = [];
if (Setting.isAdminUser(this.props.account)) {
@@ -75,9 +95,53 @@ class HomePage extends React.Component {
return items;
}
renderEChart() {
const data = this.state.dashboardData;
const chartDom = document.getElementById("echarts-chart");
const myChart = echarts.init(chartDom);
const currentDate = new Date();
const dateArray = [];
for (let i = 30; i >= 0; i--) {
const date = new Date(currentDate);
date.setDate(date.getDate() - i);
const month = parseInt(date.getMonth()) + 1;
const day = parseInt(date.getDate());
const formattedDate = `${month}-${day}`;
dateArray.push(formattedDate);
}
const option = {
title: {text: i18next.t("home:Past 30 Days")},
tooltip: {trigger: "axis"},
legend: {data: [
i18next.t("general:Users"),
i18next.t("general:Providers"),
i18next.t("general:Applications"),
i18next.t("general:Organizations"),
i18next.t("general:Subscriptions"),
]},
grid: {left: "3%", right: "4%", bottom: "3%", containLabel: true},
xAxis: {type: "category", boundaryGap: false, data: dateArray},
yAxis: {type: "value"},
series: [
{name: i18next.t("general:Organizations"), type: "line", data: data?.organizationCounts},
{name: i18next.t("general:Users"), type: "line", data: data?.userCounts},
{name: i18next.t("general:Providers"), type: "line", data: data?.providerCounts},
{name: i18next.t("general:Applications"), type: "line", data: data?.applicationCounts},
{name: i18next.t("general:Subscriptions"), type: "line", data: data?.subscriptionCounts},
],
};
myChart.setOption(option);
}
renderCards() {
if (this.state.applications === null) {
return null;
const data = this.state.dashboardData;
if (data === null) {
return (
<div style={{display: "flex", justifyContent: "center", alignItems: "center", marginTop: "10%"}}>
<Spin size="large" tip={i18next.t("login:Loading")} style={{paddingTop: "10%"}} />
</div>
);
}
const items = this.getItems();
@@ -96,24 +160,35 @@ class HomePage extends React.Component {
);
} else {
return (
<div style={{marginRight: "15px", marginLeft: "15px"}}>
<Row style={{marginLeft: "-20px", marginRight: "-20px", marginTop: "20px"}} gutter={24}>
{
items.map(item => {
return (
<SingleCard logo={item.logo} link={item.link} title={item.name} desc={item.organizer} time={item.createdTime} isSingle={items.length === 1} key={item.name} />
);
})
}
</Row>
</div>
<Row gutter={80}>
<Col span={50}>
<Card bordered={false} bodyStyle={{width: "100%", height: "150px", display: "flex", alignItems: "center", justifyContent: "center"}}>
<Statistic title={i18next.t("home:Total users")} fontSize="100px" value={data?.userCounts[30]} valueStyle={{fontSize: "30px"}} style={{width: "200px", paddingLeft: "10px"}} />
</Card>
</Col>
<Col span={50}>
<Card bordered={false} bodyStyle={{width: "100%", height: "150px", display: "flex", alignItems: "center", justifyContent: "center"}}>
<Statistic title={i18next.t("home:New users today")} fontSize="100px" value={data?.userCounts[30] - data?.userCounts[30 - 1]} valueStyle={{fontSize: "30px"}} prefix={<ArrowUpOutlined />} style={{width: "200px", paddingLeft: "10px"}} />
</Card>
</Col>
<Col span={50}>
<Card bordered={false} bodyStyle={{width: "100%", height: "150px", display: "flex", alignItems: "center", justifyContent: "center"}}>
<Statistic title={i18next.t("home:New users past 7 days")} value={data?.userCounts[30] - data?.userCounts[30 - 7]} valueStyle={{fontSize: "30px"}} prefix={<ArrowUpOutlined />} style={{width: "200px", paddingLeft: "10px"}} />
</Card>
</Col>
<Col span={50}>
<Card bordered={false} bodyStyle={{width: "100%", height: "150px", display: "flex", alignItems: "center", justifyContent: "center"}}>
<Statistic title={i18next.t("home:New users past 30 days")} value={data?.userCounts[30] - data?.userCounts[30 - 30]} valueStyle={{fontSize: "30px"}} prefix={<ArrowUpOutlined />} style={{width: "200px", paddingLeft: "10px"}} />
</Card>
</Col>
</Row>
);
}
}
render() {
return (
<div>
<div style={{display: "flex", justifyContent: "center", flexDirection: "column", alignItems: "center"}}>
<Row style={{width: "100%"}}>
<Col span={24} style={{display: "flex", justifyContent: "center"}} >
{
@@ -121,6 +196,8 @@ class HomePage extends React.Component {
}
</Col>
</Row>
<div id="echarts-chart"
style={{width: "80%", height: "400px", textAlign: "center", marginTop: "20px"}}></div>
</div>
);
}

View File

@@ -97,7 +97,7 @@ class OAuthWidget extends React.Component {
// should add the unlink user's info, cause the user may not be logged in, but a admin want to unlink the user.
user: this.props.user,
};
if (providerType === "MetaMask") {
if (providerType === "MetaMask" || providerType === "Web3Onboard") {
delWeb3AuthToken(linkedValue);
}
AuthBackend.unlink(body)
@@ -158,7 +158,12 @@ class OAuthWidget extends React.Component {
</Col>
<Col span={24 - this.props.labelSpan} >
<AccountAvatar style={{marginRight: "10px"}} size={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
<span style={{width: this.props.labelSpan === 3 ? "300px" : "200px", display: (Setting.isMobile()) ? "inline" : "inline-block"}}>
<span style={{
width: this.props.labelSpan === 3 ? "300px" : "200px",
display: (Setting.isMobile()) ? "inline" : "inline-block",
overflow: "hidden",
textOverflow: "ellipsis",
}} title={name}>
{
linkedValue === "" ? (
`(${i18next.t("general:empty")})`

View File

@@ -0,0 +1,113 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Button, Modal} from "antd";
import i18next from "i18next";
import React from "react";
import {useEffect, useState} from "react";
import {EmailMfaType} from "../../auth/MfaSetupPage";
import * as MfaBackend from "../../backend/MfaBackend";
import * as Setting from "../../Setting";
const EnableMfaModal = ({user, mfaType, onSuccess}) => {
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!open || !user) {
return;
}
MfaBackend.MfaSetupInitiate({
mfaType,
...user,
}).then((res) => {
if (res.status === "error") {
Setting.showMessage("error", i18next.t("mfa:Failed to initiate MFA"));
}
});
}, [open]);
const handleOk = () => {
setLoading(true);
MfaBackend.MfaSetupEnable({
mfaType,
...user,
}).then(res => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("general:Enabled successfully"));
setOpen(false);
onSuccess();
} else {
Setting.showMessage("error", `${i18next.t("general:Failed to enable")}: ${res.msg}`);
}
}
).finally(() => {
setLoading(false);
});
};
const handleCancel = () => {
setOpen(false);
};
const showModal = () => {
if (!isValid()) {
if (mfaType === EmailMfaType) {
Setting.showMessage("error", i18next.t("signup:Please input your Email!"));
} else {
Setting.showMessage("error", i18next.t("signup:Please input your phone number!"));
}
return;
}
setOpen(true);
};
const renderText = () => {
return (
<p>{i18next.t("mfa:Please confirm the information below")}<br />
<b>{i18next.t("general:User")}</b>: {`${user.owner}/${user.name}`}<br />
{mfaType === EmailMfaType ?
<><b>{i18next.t("general:Email")}</b> : {user.email}</> :
<><b>{i18next.t("general:Phone")}</b> : {user.phone}</>}
</p>
);
};
const isValid = () => {
if (mfaType === EmailMfaType) {
return user.email !== "";
} else {
return user.phone !== "";
}
};
return (
<React.Fragment>
<Button type="primary" onClick={showModal}>
{i18next.t("general:Enable")}
</Button>
<Modal
title={i18next.t("mfa:Enable multi-factor authentication")}
open={open}
onOk={handleOk}
onCancel={handleCancel}
confirmLoading={loading}
>
{renderText()}
</Modal>
</React.Fragment>
);
};
export default EnableMfaModal;

View File

@@ -27,6 +27,9 @@ import pt from "./locales/pt/data.json";
import it from "./locales/it/data.json";
import ms from "./locales/ms/data.json";
import tr from "./locales/tr/data.json";
import ar from "./locales/ar/data.json";
import he from "./locales/he/data.json";
import fi from "./locales/fi/data.json";
import * as Conf from "./Conf";
import {initReactI18next} from "react-i18next";
@@ -45,6 +48,9 @@ const resources = {
it: it,
ms: ms,
tr: tr,
ar: ar,
he: he,
fi: fi,
};
function initLanguage() {
@@ -103,6 +109,15 @@ function initLanguage() {
case "tr":
language = "tr";
break;
case "ar":
language = "ar";
break;
case "he":
language = "he";
break;
case "fi":
language = "fi";
break;
default:
language = Conf.DefaultLanguage;
}

1008
web/src/locales/ar/data.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
"New Adapter": "Neuer Adapter",
"Policies": "Richtlinien",
"Policies - Tooltip": "Casbin Richtlinienregeln",
"Rule type": "Rule type",
"Sync policies successfully": "Richtlinien synchronisiert"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN oder ID des LDAP-Serveradministrators",
@@ -388,6 +396,7 @@
"Continue with": "Weitermachen mit",
"Email or phone": "E-Mail oder Telefon",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Passwort vergessen?",
"Loading": "Laden",
"Logging out...": "Ausloggen...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Zurück zur Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "Die Zahlung ist fehlgeschlagen",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "Die Zahlung wird immer noch bearbeitet",
"Type - Tooltip": "Zahlungsmethode, die beim Kauf des Produkts verwendet wurde",
"You have successfully completed the payment": "Sie haben die Zahlung erfolgreich abgeschlossen",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Verkauft",
"Sold - Tooltip": "Menge verkauft",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag des Produkts",
"Test buy page..": "Testkaufseite.",
"There is no payment channel for this product.": "Es gibt keinen Zahlungskanal für dieses Produkt.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client-Geheimnis",
"Client secret 2": "Client-Secret 2",
"Client secret 2 - Tooltip": "Der zweite Client-Secret-Key",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Kopieren",
"Disable SSL": "SSL deaktivieren",
"Disable SSL - Tooltip": "Ob die Deaktivierung des SSL-Protokolls bei der Kommunikation mit dem STMP-Server erfolgen soll",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Anmeldeverfahren, QR-Code oder Silent-Login",
"New Provider": "Neuer Provider",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "parsen",
"Parse metadata successfully": "Metadaten erfolgreich analysiert",
"Path prefix": "Pfadpräfix",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo-URL",
"UserInfo URL - Tooltip": "UserInfo-URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Shared)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Tabelle",
"Table - Tooltip": "Name der Datenbanktabelle",
"Table columns": "Tabellenspalten",
"Table columns - Tooltip": "Spalten in der Tabelle, die an der Datensynchronisierung beteiligt sind. Spalten, die nicht an der Synchronisierung beteiligt sind, müssen nicht hinzugefügt werden",
"Table primary key": "Primärschlüssel der Tabelle",
"Table primary key - Tooltip": "Primärschlüssel in einer Tabelle, wie beispielsweise eine ID"
"Table columns - Tooltip": "Spalten in der Tabelle, die an der Datensynchronisierung beteiligt sind. Spalten, die nicht an der Synchronisierung beteiligt sind, müssen nicht hinzugefügt werden"
},
"system": {
"API Latency": "API Latenz",

View File

@@ -11,6 +11,7 @@
"New Adapter": "New Adapter",
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN or ID of the LDAP server administrator",
@@ -388,6 +396,7 @@
"Continue with": "Continue with",
"Email or phone": "Email or phone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
"Loading": "Loading",
"Logging out...": "Logging out...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Return to Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "The payment has failed",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "The payment is still under processing",
"Type - Tooltip": "Payment method used when purchasing the product",
"You have successfully completed the payment": "You have successfully completed the payment",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client secret",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "The second client secret key",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Login method, QR code or silent login",
"New Provider": "New Provider",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parse",
"Parse metadata successfully": "Parse metadata successfully",
"Path prefix": "Path prefix",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Shared)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Table",
"Table - Tooltip": "Name of database table",
"Table columns": "Table columns",
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added",
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key, such as id"
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added"
},
"system": {
"API Latency": "API Latency",

View File

@@ -11,6 +11,7 @@
"New Adapter": "Nuevo adaptador",
"Policies": "Políticas",
"Policies - Tooltip": "Reglas de política de Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Sincronizar políticas correctamente"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Administrador",
"Admin - Tooltip": "CN o ID del administrador del servidor LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Continúe con",
"Email or phone": "Correo electrónico o teléfono",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "¿Olvidaste tu contraseña?",
"Loading": "Cargando",
"Logging out...": "Cerrando sesión...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Regresar al sitio web",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "El pago ha fallado",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "El pago aún está en proceso",
"Type - Tooltip": "Método de pago utilizado al comprar el producto",
"You have successfully completed the payment": "Has completado el pago exitosamente",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Vendido",
"Sold - Tooltip": "Cantidad vendida",
"Stripe": "Stripe",
"Tag - Tooltip": "Etiqueta de producto",
"Test buy page..": "Página de compra de prueba.",
"There is no payment channel for this product.": "No hay canal de pago para este producto.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Secreto del cliente",
"Client secret 2": "Secreto del cliente 2",
"Client secret 2 - Tooltip": "La segunda clave secreta del cliente",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copiar",
"Disable SSL": "Desactivar SSL",
"Disable SSL - Tooltip": "¿Hay que desactivar el protocolo SSL al comunicarse con el servidor STMP?",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Método de inicio de sesión, código QR o inicio de sesión silencioso",
"New Provider": "Nuevo proveedor",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Analizar",
"Parse metadata successfully": "Analizar los metadatos con éxito",
"Path prefix": "Prefijo de ruta",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL de información del usuario",
"UserInfo URL - Tooltip": "URL de información de usuario",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "administrador (compartido)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Mesa",
"Table - Tooltip": "Nombre de la tabla de la base de datos",
"Table columns": "Columnas de tabla",
"Table columns - Tooltip": "Columnas en la tabla involucradas en la sincronización de datos. Las columnas que no estén involucradas en la sincronización no necesitan ser añadidas",
"Table primary key": "Clave primaria de la tabla",
"Table primary key - Tooltip": "Clave primaria de la tabla, como id"
"Table columns - Tooltip": "Columnas en la tabla involucradas en la sincronización de datos. Las columnas que no estén involucradas en la sincronización no necesitan ser añadidas"
},
"system": {
"API Latency": "Retraso API",

1008
web/src/locales/fi/data.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
"New Adapter": "Nouvel adaptateur",
"Policies": "Politiques",
"Policies - Tooltip": "Règles de politique Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Synchronisation des politiques réussie"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN ou ID de l'administrateur du serveur LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Continuer avec",
"Email or phone": "Email ou téléphone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Mot de passe oublié ?",
"Loading": "Chargement",
"Logging out...": "Déconnexion...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Retourner sur le site web",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "Le paiement a échoué",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "Le paiement est encore en cours de traitement",
"Type - Tooltip": "Méthode de paiement utilisée lors de l'achat du produit",
"You have successfully completed the payment": "Vous avez effectué le paiement avec succès",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Vendu",
"Sold - Tooltip": "Quantité vendue",
"Stripe": "Stripe",
"Tag - Tooltip": "Étiquette de produit",
"Test buy page..": "Page d'achat de test.",
"There is no payment channel for this product.": "Il n'y a aucun canal de paiement pour ce produit.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Secret client",
"Client secret 2": "Secret client 2",
"Client secret 2 - Tooltip": "La deuxième clé secrète du client",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copie",
"Disable SSL": "Désactiver SSL",
"Disable SSL - Tooltip": "Doit-on désactiver le protocole SSL lors de la communication avec le serveur STMP ?",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Méthode de connexion, code QR ou connexion silencieuse",
"New Provider": "Nouveau fournisseur",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parser",
"Parse metadata successfully": "Parcourir les métadonnées avec succès",
"Path prefix": "Préfixe de chemin",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL d'informations utilisateur",
"UserInfo URL - Tooltip": "URL d'informations sur l'utilisateur",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Partagé)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Table",
"Table - Tooltip": "Nom de la table de base de données",
"Table columns": "Colonnes de table",
"Table columns - Tooltip": "Colonnes dans la table impliquées dans la synchronisation des données. Les colonnes qui ne sont pas impliquées dans la synchronisation n'ont pas besoin d'être ajoutées",
"Table primary key": "Clé primaire de table",
"Table primary key - Tooltip": "Clé primaire de la table, telle que l'id"
"Table columns - Tooltip": "Colonnes dans la table impliquées dans la synchronisation des données. Les colonnes qui ne sont pas impliquées dans la synchronisation n'ont pas besoin d'être ajoutées"
},
"system": {
"API Latency": "Retard API",

1008
web/src/locales/he/data.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
"New Adapter": "Adapter Baru",
"Policies": "Kebijakan",
"Policies - Tooltip": "Kebijakan aturan Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Sinkronisasi kebijakan berhasil dilakukan"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN atau ID dari administrator server LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Lanjutkan dengan",
"Email or phone": "Email atau telepon",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Lupa kata sandi?",
"Loading": "Memuat",
"Logging out...": "Keluar...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Kembali ke Situs Web",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "Pembayaran gagal",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "Pembayaran masih dalam proses",
"Type - Tooltip": "Metode pembayaran yang digunakan saat membeli produk",
"You have successfully completed the payment": "Anda telah berhasil menyelesaikan pembayaran",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Terjual",
"Sold - Tooltip": "Jumlah terjual",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag produk",
"Test buy page..": "Halaman pembelian uji coba.",
"There is no payment channel for this product.": "Tidak ada saluran pembayaran untuk produk ini.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Rahasia klien",
"Client secret 2": "Rahasia klien 2",
"Client secret 2 - Tooltip": "Kunci rahasia klien kedua",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Salin",
"Disable SSL": "Menonaktifkan SSL",
"Disable SSL - Tooltip": "Apakah perlu menonaktifkan protokol SSL saat berkomunikasi dengan server STMP?",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Metode login, kode QR atau login tanpa suara",
"New Provider": "Penyedia Baru",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parse: Memecah atau mengurai data atau teks menjadi bagian-bagian yang lebih kecil dan lebih mudah dipahami atau dimanipulasi",
"Parse metadata successfully": "Berhasil mem-parse metadata",
"Path prefix": "Awalan jalur",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL UserInfo",
"UserInfo URL - Tooltip": "URL Informasi Pengguna",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "Admin (Berbagi)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Tabel",
"Table - Tooltip": "Nama tabel database",
"Table columns": "Kolom tabel",
"Table columns - Tooltip": "Kolom pada tabel yang terlibat dalam sinkronisasi data. Kolom yang tidak terlibat dalam sinkronisasi tidak perlu ditambahkan",
"Table primary key": "Kunci utama tabel",
"Table primary key - Tooltip": "Kunci primer tabel, seperti id"
"Table columns - Tooltip": "Kolom pada tabel yang terlibat dalam sinkronisasi data. Kolom yang tidak terlibat dalam sinkronisasi tidak perlu ditambahkan"
},
"system": {
"API Latency": "API Latency",

View File

@@ -11,6 +11,7 @@
"New Adapter": "New Adapter",
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN or ID of the LDAP server administrator",
@@ -388,6 +396,7 @@
"Continue with": "Continue with",
"Email or phone": "Email or phone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
"Loading": "Loading",
"Logging out...": "Logging out...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Return to Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "The payment has failed",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "The payment is still under processing",
"Type - Tooltip": "Payment method used when purchasing the product",
"You have successfully completed the payment": "You have successfully completed the payment",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client secret",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "The second client secret key",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Login method, QR code or silent login",
"New Provider": "New Provider",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parse",
"Parse metadata successfully": "Parse metadata successfully",
"Path prefix": "Path prefix",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Shared)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Table",
"Table - Tooltip": "Name of database table",
"Table columns": "Table columns",
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added",
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key, such as id"
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added"
},
"system": {
"API Latency": "API Latency",

View File

@@ -11,6 +11,7 @@
"New Adapter": "新しいアダプター",
"Policies": "政策",
"Policies - Tooltip": "Casbinのポリシールール",
"Rule type": "Rule type",
"Sync policies successfully": "ポリシーを同期できました"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "LDAPサーバー管理者のCNまたはID",
@@ -388,6 +396,7 @@
"Continue with": "続ける",
"Email or phone": "メールまたは電話",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "パスワードを忘れましたか?",
"Loading": "ローディング",
"Logging out...": "ログアウト中...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "ウェブサイトに戻る",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "支払いに失敗しました",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "支払いはまだ処理中です",
"Type - Tooltip": "製品を購入する際に使用される支払方法",
"You have successfully completed the payment": "あなたは支払いを正常に完了しました",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "売れました",
"Sold - Tooltip": "販売数量",
"Stripe": "Stripe",
"Tag - Tooltip": "製品のタグ",
"Test buy page..": "テスト購入ページ。",
"There is no payment channel for this product.": "この製品には支払いチャネルがありません。",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "クライアント秘密鍵",
"Client secret 2": "クライアントシークレット2",
"Client secret 2 - Tooltip": "第二クライアント秘密鍵",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "コピー",
"Disable SSL": "SSLを無効にする",
"Disable SSL - Tooltip": "SMTPサーバーと通信する場合にSSLプロトコルを無効にするかどうか",
@@ -682,6 +696,8 @@
"Method - Tooltip": "ログイン方法、QRコードまたはサイレントログイン",
"New Provider": "新しい提供者",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "パースする",
"Parse metadata successfully": "メタデータを正常に解析しました",
"Path prefix": "パスプレフィックス",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URLを日本語に翻訳すると、「ユーザー情報のURL」となります",
"UserInfo URL - Tooltip": "ユーザー情報URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "管理者(共有)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "テーブル",
"Table - Tooltip": "データベーステーブル名",
"Table columns": "テーブルの列",
"Table columns - Tooltip": "テーブルで同期データに関与する列。同期に関係のない列は追加する必要はありません",
"Table primary key": "テーブルの主キー",
"Table primary key - Tooltip": "テーブルのプライマリキー、例えばid"
"Table columns - Tooltip": "テーブルで同期データに関与する列。同期に関係のない列は追加する必要はありません"
},
"system": {
"API Latency": "API遅延",

View File

@@ -11,6 +11,7 @@
"New Adapter": "새로운 어댑터",
"Policies": "정책",
"Policies - Tooltip": "Casbin 정책 규칙",
"Rule type": "Rule type",
"Sync policies successfully": "정책을 성공적으로 동기화했습니다"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "LDAP 서버 관리자의 CN 또는 ID",
@@ -388,6 +396,7 @@
"Continue with": "계속하다",
"Email or phone": "이메일 또는 전화",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "비밀번호를 잊으셨나요?",
"Loading": "로딩 중입니다",
"Logging out...": "로그아웃 중...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "웹 사이트로 돌아가기",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "결제가 실패했습니다",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "지불은 아직 처리 중입니다",
"Type - Tooltip": "제품을 구매할 때 사용되는 결제 방법",
"You have successfully completed the payment": "당신은 결제를 성공적으로 완료하셨습니다",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "팔렸습니다",
"Sold - Tooltip": "판매량",
"Stripe": "Stripe",
"Tag - Tooltip": "제품 태그",
"Test buy page..": "시험 구매 페이지.",
"There is no payment channel for this product.": "이 제품에 대한 결제 채널이 없습니다.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "클라이언트 비밀키",
"Client secret 2": "클라이언트 비밀번호 2",
"Client secret 2 - Tooltip": "두 번째 클라이언트 비밀 키",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "복사하다",
"Disable SSL": "SSL을 사용하지 않도록 설정하십시오",
"Disable SSL - Tooltip": "STMP 서버와 통신할 때 SSL 프로토콜을 비활성화할지 여부",
@@ -682,6 +696,8 @@
"Method - Tooltip": "로그인 방법, QR 코드 또는 음성 로그인",
"New Provider": "새로운 공급 업체",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "파싱",
"Parse metadata successfully": "메타데이터를 성공적으로 분석했습니다",
"Path prefix": "경로 접두어",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "사용자 정보 URL",
"UserInfo URL - Tooltip": "UserInfo URL: 사용자 정보 URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "관리자 (공유)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "테이블",
"Table - Tooltip": "데이터베이스 테이블 이름",
"Table columns": "테이블 열",
"Table columns - Tooltip": "데이터 동기화에 관련된 테이블의 열들입니다. 동기화에 관련되지 않은 열은 추가할 필요가 없습니다",
"Table primary key": "테이블 기본키",
"Table primary key - Tooltip": "테이블의 기본 키, 예를 들어 id"
"Table columns - Tooltip": "데이터 동기화에 관련된 테이블의 열들입니다. 동기화에 관련되지 않은 열은 추가할 필요가 없습니다"
},
"system": {
"API Latency": "API 지연",

View File

@@ -11,6 +11,7 @@
"New Adapter": "New Adapter",
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN or ID of the LDAP server administrator",
@@ -388,6 +396,7 @@
"Continue with": "Continue with",
"Email or phone": "Email or phone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
"Loading": "Loading",
"Logging out...": "Logging out...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Return to Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "The payment has failed",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "The payment is still under processing",
"Type - Tooltip": "Payment method used when purchasing the product",
"You have successfully completed the payment": "You have successfully completed the payment",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client secret",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "The second client secret key",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Login method, QR code or silent login",
"New Provider": "New Provider",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parse",
"Parse metadata successfully": "Parse metadata successfully",
"Path prefix": "Path prefix",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Shared)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Table",
"Table - Tooltip": "Name of database table",
"Table columns": "Table columns",
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added",
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key, such as id"
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added"
},
"system": {
"API Latency": "API Latency",

View File

@@ -11,6 +11,7 @@
"New Adapter": "Novo Adaptador",
"Policies": "Políticas",
"Policies - Tooltip": "Regras de política do Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Políticas sincronizadas com sucesso"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Administrador",
"Admin - Tooltip": "CN ou ID do administrador do servidor LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Continuar com",
"Email or phone": "Email ou telefone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Esqueceu a senha?",
"Loading": "Carregando",
"Logging out...": "Saindo...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Retornar ao Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "O pagamento falhou",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "O pagamento ainda está sendo processado",
"Type - Tooltip": "Método de pagamento utilizado ao comprar o produto",
"You have successfully completed the payment": "Você concluiu o pagamento com sucesso",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Vendido",
"Sold - Tooltip": "Quantidade vendida",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag do produto",
"Test buy page..": "Página de teste de compra...",
"There is no payment channel for this product.": "Não há canal de pagamento disponível para este produto.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Segredo do cliente",
"Client secret 2": "Segredo do cliente 2",
"Client secret 2 - Tooltip": "A segunda chave secreta do cliente",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copiar",
"Disable SSL": "Desabilitar SSL",
"Disable SSL - Tooltip": "Se deve desabilitar o protocolo SSL ao comunicar com o servidor SMTP",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Método de login, código QR ou login silencioso",
"New Provider": "Novo Provedor",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Analisar",
"Parse metadata successfully": "Metadados analisados com sucesso",
"Path prefix": "Prefixo do caminho",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL do UserInfo",
"UserInfo URL - Tooltip": "URL do UserInfo",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Compartilhado)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Tabela",
"Table - Tooltip": "Nome da tabela no banco de dados",
"Table columns": "Colunas da tabela",
"Table columns - Tooltip": "Colunas na tabela envolvidas na sincronização de dados. Colunas que não estão envolvidas na sincronização não precisam ser adicionadas",
"Table primary key": "Chave primária da tabela",
"Table primary key - Tooltip": "Chave primária da tabela, como id"
"Table columns - Tooltip": "Colunas na tabela envolvidas na sincronização de dados. Colunas que não estão envolvidas na sincronização não precisam ser adicionadas"
},
"system": {
"API Latency": "Latência da API",

View File

@@ -11,6 +11,7 @@
"New Adapter": "Новый адаптер",
"Policies": "Политика",
"Policies - Tooltip": "Правила политики Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Успешно синхронизированы политики"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN или ID администратора сервера LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Продолжайте с",
"Email or phone": "Электронная почта или телефон",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Забыли пароль?",
"Loading": "Загрузка",
"Logging out...": "Выход...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Вернуться на веб-сайт",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "Оплата не удалась",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "Оплата все еще обрабатывается",
"Type - Tooltip": "Способ оплаты, используемый при покупке товара",
"You have successfully completed the payment": "Вы успешно произвели платеж",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Продано",
"Sold - Tooltip": "Количество проданных",
"Stripe": "Stripe",
"Tag - Tooltip": "Метка продукта",
"Test buy page..": "Страница для тестовой покупки.",
"There is no payment channel for this product.": "Для этого продукта нет канала оплаты.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Клиентский секрет",
"Client secret 2": "Секрет клиента 2",
"Client secret 2 - Tooltip": "Второй секретный ключ клиента",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Копировать",
"Disable SSL": "Отключить SSL",
"Disable SSL - Tooltip": "Нужно ли отключать протокол SSL при общении с SMTP сервером?",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Метод входа, QR-код или беззвучный вход",
"New Provider": "Новый провайдер",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Спарсить",
"Parse metadata successfully": "Успешно обработана метаданные",
"Path prefix": "Префикс пути",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL информации о пользователе",
"UserInfo URL - Tooltip": "URL пользовательской информации (URL информации о пользователе)",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "администратор (общий)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Стол",
"Table - Tooltip": "Название таблицы базы данных",
"Table columns": "Столбцы таблицы",
"Table columns - Tooltip": "Столбцы в таблице, участвующие в синхронизации данных. Столбцы, не участвующие в синхронизации, не нужно добавлять",
"Table primary key": "Первичный ключ таблицы",
"Table primary key - Tooltip": "Идентификатор (id) - основной ключ таблицы"
"Table columns - Tooltip": "Столбцы в таблице, участвующие в синхронизации данных. Столбцы, не участвующие в синхронизации, не нужно добавлять"
},
"system": {
"API Latency": "Задержка API",

View File

@@ -11,6 +11,7 @@
"New Adapter": "New Adapter",
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN or ID of the LDAP server administrator",
@@ -388,6 +396,7 @@
"Continue with": "Continue with",
"Email or phone": "Email or phone",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
"Loading": "Loading",
"Logging out...": "Logging out...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Return to Website",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "The payment has failed",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "The payment is still under processing",
"Type - Tooltip": "Payment method used when purchasing the product",
"You have successfully completed the payment": "You have successfully completed the payment",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client secret",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "The second client secret key",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Login method, QR code or silent login",
"New Provider": "New Provider",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Parse",
"Parse metadata successfully": "Parse metadata successfully",
"Path prefix": "Path prefix",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin (Shared)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Table",
"Table - Tooltip": "Name of database table",
"Table columns": "Table columns",
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added",
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key, such as id"
"Table columns - Tooltip": "Columns in the table involved in data synchronization. Columns that are not involved in synchronization do not need to be added"
},
"system": {
"API Latency": "API Latency",

View File

@@ -11,6 +11,7 @@
"New Adapter": "Bộ chuyển đổi mới",
"Policies": "Chính sách",
"Policies - Tooltip": "Quy tắc chính sách Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Đồng bộ chính sách thành công"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "Show all",
"Virtual": "Virtual"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "Admin",
"Admin - Tooltip": "CN hoặc ID của quản trị viên máy chủ LDAP",
@@ -388,6 +396,7 @@
"Continue with": "Tiếp tục với",
"Email or phone": "Email hoặc điện thoại",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Quên mật khẩu?",
"Loading": "Đang tải",
"Logging out...": "Đăng xuất ...",
@@ -431,6 +440,7 @@
"Passcode": "Passcode",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
"Please confirm the information below": "Please confirm the information below",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
"Recovery code": "Recovery code",
@@ -523,6 +533,7 @@
"Return to Website": "Trở lại trang web",
"The payment has been canceled": "The payment has been canceled",
"The payment has failed": "Thanh toán đã thất bại",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "Thanh toán vẫn đang được xử lý",
"Type - Tooltip": "Phương thức thanh toán được sử dụng khi mua sản phẩm",
"You have successfully completed the payment": "Bạn đã hoàn thành thanh toán thành công",
@@ -604,6 +615,7 @@
"SKU": "SKU",
"Sold": "Đã bán",
"Sold - Tooltip": "Số lượng bán ra",
"Stripe": "Stripe",
"Tag - Tooltip": "Nhãn sản phẩm",
"Test buy page..": "Trang mua thử.",
"There is no payment channel for this product.": "Không có kênh thanh toán cho sản phẩm này.",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Mã bí mật khách hàng",
"Client secret 2": "Khóa bí mật của khách hàng 2",
"Client secret 2 - Tooltip": "Khóa bí mật thứ hai của khách hàng",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Sao chép",
"Disable SSL": "Vô hiệu hóa SSL",
"Disable SSL - Tooltip": "Có nên vô hiệu hóa giao thức SSL khi giao tiếp với máy chủ STMP hay không?",
@@ -682,6 +696,8 @@
"Method - Tooltip": "Phương thức đăng nhập, mã QR hoặc đăng nhập im lặng",
"New Provider": "Nhà cung cấp mới",
"Normal": "Normal",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "Phân tích cú pháp",
"Parse metadata successfully": "Phân tích siêu dữ liệu thành công",
"Path prefix": "Tiền tố đường dẫn",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "Đường dẫn UserInfo",
"UserInfo URL - Tooltip": "Địa chỉ URL của Thông tin người dùng",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "quản trị viên (Chung)"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "Bàn",
"Table - Tooltip": "Tên của bảng cơ sở dữ liệu",
"Table columns": "Các cột bảng",
"Table columns - Tooltip": "Cột trong bảng liên quan đến đồng bộ dữ liệu. Các cột không liên quan đến đồng bộ hóa không cần được thêm vào",
"Table primary key": "Khóa chính của bảng",
"Table primary key - Tooltip": "Khóa chính của bảng, ví dụ như id"
"Table columns - Tooltip": "Cột trong bảng liên quan đến đồng bộ dữ liệu. Các cột không liên quan đến đồng bộ hóa không cần được thêm vào"
},
"system": {
"API Latency": "Độ trễ API",

View File

@@ -11,6 +11,7 @@
"New Adapter": "添加适配器",
"Policies": "策略",
"Policies - Tooltip": "Casbin策略规则",
"Rule type": "策略类型",
"Sync policies successfully": "同步策略成功"
},
"application": {
@@ -353,6 +354,13 @@
"Show all": "显示全部",
"Virtual": "虚拟组"
},
"home": {
"New users past 30 days": "New users past 30 days",
"New users past 7 days": "New users past 7 days",
"New users today": "New users today",
"Past 30 Days": "Past 30 Days",
"Total users": "Total users"
},
"ldap": {
"Admin": "管理员",
"Admin - Tooltip": "LDAP服务器管理员的CN或ID",
@@ -388,6 +396,7 @@
"Continue with": "使用以下账号继续",
"Email or phone": "Email或手机号",
"Failed to obtain MetaMask authorization": "获取MetaMask授权失败",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "忘记密码?",
"Loading": "加载中",
"Logging out...": "正在退出登录...",
@@ -431,6 +440,7 @@
"Passcode": "认证码",
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "请先绑定邮箱,之后会自动使用该邮箱作为多因素认证的方式",
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "请先绑定手机号,之后会自动使用该手机号作为多因素认证的方式",
"Please confirm the information below": "请确认以下信息",
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "请保存此恢复代码。一旦您的设备无法提供身份验证码,您可以通过此恢复码重置多因素认证",
"Protect your account with Multi-factor authentication": "通过多因素认证保护您的帐户",
"Recovery code": "恢复码",
@@ -523,6 +533,7 @@
"Return to Website": "返回原网站",
"The payment has been canceled": "付款已取消",
"The payment has failed": "支付失败",
"The payment has time out": "The payment has time out",
"The payment is still under processing": "支付正在处理",
"Type - Tooltip": "商品购买时的支付方式",
"You have successfully completed the payment": "支付成功",
@@ -604,6 +615,7 @@
"SKU": "货号",
"Sold": "售出",
"Sold - Tooltip": "已售出的数量",
"Stripe": "Stripe",
"Tag - Tooltip": "商品类别",
"Test buy page..": "测试购买页面..",
"There is no payment channel for this product.": "该商品没有付款方式。",
@@ -648,6 +660,8 @@
"Client secret - Tooltip": "Client secret",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "第二个Client secret",
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "复制",
"Disable SSL": "禁用SSL",
"Disable SSL - Tooltip": "与STMP服务器通信时是否禁用SSL协议",
@@ -682,6 +696,8 @@
"Method - Tooltip": "登录方法,二维码或者静默授权登录",
"New Provider": "添加提供商",
"Normal": "标准",
"Parameter name": "Parameter name",
"Parameter name - Tooltip": "Parameter name - Tooltip",
"Parse": "解析",
"Parse metadata successfully": "解析元数据成功",
"Path prefix": "路径前缀",
@@ -758,6 +774,8 @@
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "自定义OAuth的UserInfo URL",
"Wallets": "Wallets",
"Wallets - Tooltip": "Wallets - Tooltip",
"admin (Shared)": "admin共享"
},
"record": {
@@ -849,9 +867,7 @@
"Table": "表名",
"Table - Tooltip": "数据库表名",
"Table columns": "表格列",
"Table columns - Tooltip": "参与数据同步的表格列,不参与同步的列不需要添加",
"Table primary key": "表主键",
"Table primary key - Tooltip": "表主键如id等"
"Table columns - Tooltip": "参与数据同步的表格列,不参与同步的列不需要添加"
},
"system": {
"API Latency": "API 延迟",

View File

@@ -33,11 +33,11 @@ class PolicyTable extends React.Component {
}
count = 0;
pageSize = 10;
pageSize = 100;
getIndex(index) {
// Need to be used in all place when modify table. Parameter is the row index in table, need to calculate the index in dataSource.
return index + (this.state.page - 1) * 10;
return index + (this.state.page - 1) * this.pageSize;
}
UNSAFE_componentWillMount() {
@@ -165,7 +165,7 @@ class PolicyTable extends React.Component {
renderTable(table) {
const columns = [
{
title: "Rule Type",
title: i18next.t("adapter:Rule type"),
dataIndex: "Ptype",
width: "100px",
// render: (text, record, index) => {
@@ -270,8 +270,9 @@ class PolicyTable extends React.Component {
},
},
{
title: "Option",
key: "option",
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "100px",
render: (text, record, index) => {
const editable = this.isEditing(index);
@@ -304,7 +305,6 @@ class PolicyTable extends React.Component {
onChange: (page) => this.setState({
page: page,
}),
disabled: this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name}),
current: this.state.page,
}}
columns={columns} dataSource={table} rowKey="key" size="middle" bordered

File diff suppressed because it is too large Load Diff