mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-01 01:30:31 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9f3ee275a8 | ||
![]() |
fcda64ad7d | ||
![]() |
d815bf92bd | ||
![]() |
7867060b71 | ||
![]() |
8890d1d7c7 | ||
![]() |
6e6a0a074a | ||
![]() |
cff3007992 | ||
![]() |
fe448cbcf4 | ||
![]() |
2ab25df950 | ||
![]() |
b895926754 | ||
![]() |
5bb7a4153f | ||
![]() |
b7cd598ee8 | ||
![]() |
b10fb97c92 |
@@ -31,6 +31,8 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
|
||||
return NewAliyunCaptchaProvider()
|
||||
} else if captchaType == "GEETEST" {
|
||||
return NewGEETESTCaptchaProvider()
|
||||
} else if captchaType == "Cloudflare Turnstile" {
|
||||
return NewCloudflareTurnstileProvider()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
66
captcha/turnstile.go
Normal file
66
captcha/turnstile.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const CloudflareTurnstileVerifyUrl = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
|
||||
|
||||
type CloudflareTurnstileProvider struct{}
|
||||
|
||||
func NewCloudflareTurnstileProvider() *CloudflareTurnstileProvider {
|
||||
captcha := &CloudflareTurnstileProvider{}
|
||||
return captcha
|
||||
}
|
||||
|
||||
func (captcha *CloudflareTurnstileProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
|
||||
reqData := url.Values{
|
||||
"secret": {clientSecret},
|
||||
"response": {token},
|
||||
}
|
||||
resp, err := http.PostForm(CloudflareTurnstileVerifyUrl, reqData)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
type captchaResponse struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCodes []string `json:"error-codes"`
|
||||
}
|
||||
captchaResp := &captchaResponse{}
|
||||
err = json.Unmarshal(body, captchaResp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(captchaResp.ErrorCodes) > 0 {
|
||||
return false, errors.New(strings.Join(captchaResp.ErrorCodes, ","))
|
||||
}
|
||||
|
||||
return captchaResp.Success, nil
|
||||
}
|
@@ -21,3 +21,4 @@ isDemoMode = false
|
||||
batchSize = 100
|
||||
ldapServerPort = 389
|
||||
languages = en,zh,es,fr,de,ja,ko,ru
|
||||
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
|
||||
|
25
conf/conf.go
25
conf/conf.go
@@ -15,6 +15,7 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
@@ -24,6 +25,15 @@ import (
|
||||
"github.com/beego/beego"
|
||||
)
|
||||
|
||||
type Quota struct {
|
||||
Organization int `json:"organization"`
|
||||
User int `json:"user"`
|
||||
Application int `json:"application"`
|
||||
Provider int `json:"provider"`
|
||||
}
|
||||
|
||||
var quota = &Quota{-1, -1, -1, -1}
|
||||
|
||||
func init() {
|
||||
// this array contains the beego configuration items that may be modified via env
|
||||
presetConfigItems := []string{"httpport", "appname"}
|
||||
@@ -35,6 +45,17 @@ func init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
initQuota()
|
||||
}
|
||||
|
||||
func initQuota() {
|
||||
res := beego.AppConfig.String("quota")
|
||||
if res != "" {
|
||||
err := json.Unmarshal([]byte(res), quota)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetConfigString(key string) string {
|
||||
@@ -95,3 +116,7 @@ func GetConfigBatchSize() int {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func GetConfigQuota() *Quota {
|
||||
return quota
|
||||
}
|
||||
|
@@ -93,3 +93,19 @@ func TestGetConfBool(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigQuota(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
description string
|
||||
expected *Quota
|
||||
}{
|
||||
{"default", &Quota{-1, -1, -1, -1}},
|
||||
}
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
for _, scenery := range scenarios {
|
||||
quota := GetConfigQuota()
|
||||
assert.Equal(t, scenery.expected, quota)
|
||||
}
|
||||
}
|
||||
|
@@ -167,6 +167,12 @@ func (c *ApiController) AddApplication() {
|
||||
return
|
||||
}
|
||||
|
||||
count := object.GetApplicationCount("", "", "")
|
||||
if err := checkQuotaForApplication(count); err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -89,6 +90,69 @@ func (c *ApiController) SyncPolicies() {
|
||||
id := c.Input().Get("id")
|
||||
adapter := object.GetCasbinAdapter(id)
|
||||
|
||||
c.Data["json"] = object.SyncPolicies(adapter)
|
||||
policies, err := object.SyncPolicies(adapter)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = policies
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) UpdatePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
adapter := object.GetCasbinAdapter(id)
|
||||
var policies []xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.UpdatePolicy(util.CasbinToSlice(policies[0]), util.CasbinToSlice(policies[1]), adapter)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = wrapActionResponse(affected)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) AddPolicy() {
|
||||
id := c.Input().Get("id")
|
||||
adapter := object.GetCasbinAdapter(id)
|
||||
var policy xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.AddPolicy(util.CasbinToSlice(policy), adapter)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = wrapActionResponse(affected)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) RemovePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
adapter := object.GetCasbinAdapter(id)
|
||||
var policy xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.RemovePolicy(util.CasbinToSlice(policy), adapter)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = wrapActionResponse(affected)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -99,6 +99,12 @@ func (c *ApiController) AddOrganization() {
|
||||
return
|
||||
}
|
||||
|
||||
count := object.GetOrganizationCount("", "", "")
|
||||
if err := checkQuotaForOrganization(count); err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -65,6 +65,20 @@ func (c *ApiController) GetPermissionsBySubmitter() {
|
||||
return
|
||||
}
|
||||
|
||||
// GetPermissionsByRole
|
||||
// @Title GetPermissionsByRole
|
||||
// @Tag Permission API
|
||||
// @Description get permissions by role
|
||||
// @Param id query string true "The id of the role"
|
||||
// @Success 200 {array} object.Permission The Response object
|
||||
// @router /get-permissions-by-role [get]
|
||||
func (c *ApiController) GetPermissionsByRole() {
|
||||
id := c.Input().Get("id")
|
||||
permissions := object.GetPermissionsByRole(id)
|
||||
c.ResponseOk(permissions, len(permissions))
|
||||
return
|
||||
}
|
||||
|
||||
// GetPermission
|
||||
// @Title GetPermission
|
||||
// @Tag Permission API
|
||||
|
@@ -122,6 +122,12 @@ func (c *ApiController) AddProvider() {
|
||||
return
|
||||
}
|
||||
|
||||
count := object.GetProviderCount("", "", "")
|
||||
if err := checkQuotaForProvider(count); err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@@ -171,6 +171,20 @@ func (c *ApiController) UploadResource() {
|
||||
fileType, _ = util.GetOwnerAndNameFromId(mimeType)
|
||||
}
|
||||
|
||||
if tag != "avatar" && tag != "termsOfUse" {
|
||||
ext := filepath.Ext(filepath.Base(fullFilePath))
|
||||
index := len(fullFilePath) - len(ext)
|
||||
for i := 1; ; i++ {
|
||||
_, objectKey := object.GetUploadFileUrl(provider, fullFilePath, true)
|
||||
if object.GetResourceCount(owner, username, "name", objectKey) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// duplicated fullFilePath found, change it
|
||||
fullFilePath = fullFilePath[:index] + fmt.Sprintf("-%d", i) + ext
|
||||
}
|
||||
}
|
||||
|
||||
fileUrl, objectKey, err := object.UploadFileSafe(provider, fullFilePath, fileBuffer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
@@ -183,6 +183,12 @@ func (c *ApiController) AddUser() {
|
||||
return
|
||||
}
|
||||
|
||||
count := object.GetUserCount("", "", "")
|
||||
if err := checkQuotaForUser(count); err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
msg := object.CheckUsername(user.Name, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
|
@@ -153,3 +153,47 @@ func (c *ApiController) GetProviderFromContext(category string) (*object.Provide
|
||||
|
||||
return provider, user, true
|
||||
}
|
||||
|
||||
func checkQuotaForApplication(count int) error {
|
||||
quota := conf.GetConfigQuota().Application
|
||||
if quota == -1 {
|
||||
return nil
|
||||
}
|
||||
if count >= quota {
|
||||
return fmt.Errorf("application quota is exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkQuotaForOrganization(count int) error {
|
||||
quota := conf.GetConfigQuota().Organization
|
||||
if quota == -1 {
|
||||
return nil
|
||||
}
|
||||
if count >= quota {
|
||||
return fmt.Errorf("organization quota is exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkQuotaForProvider(count int) error {
|
||||
quota := conf.GetConfigQuota().Provider
|
||||
if quota == -1 {
|
||||
return nil
|
||||
}
|
||||
if count >= quota {
|
||||
return fmt.Errorf("provider quota is exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkQuotaForUser(count int) error {
|
||||
quota := conf.GetConfigQuota().User
|
||||
if quota == -1 {
|
||||
return nil
|
||||
}
|
||||
if count >= quota {
|
||||
return fmt.Errorf("user quota is exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -92,6 +92,10 @@ func (c *ApiController) SendVerificationCode() {
|
||||
user := c.getCurrentUser()
|
||||
application := object.GetApplication(applicationId)
|
||||
organization := object.GetOrganization(fmt.Sprintf("%s/%s", application.Owner, application.Organization))
|
||||
if organization == nil {
|
||||
c.ResponseError(c.T("OrgErr.DoNotExist"))
|
||||
return
|
||||
}
|
||||
|
||||
if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil {
|
||||
c.ResponseError(c.T("LoginErr.LoginFirst"))
|
||||
@@ -114,6 +118,12 @@ func (c *ApiController) SendVerificationCode() {
|
||||
return
|
||||
}
|
||||
|
||||
userByEmail := object.GetUserByEmail(organization.Name, dest)
|
||||
if userByEmail == nil {
|
||||
c.ResponseError(c.T("UserErr.DoNotExistSignUp"))
|
||||
return
|
||||
}
|
||||
|
||||
provider := application.GetEmailProvider()
|
||||
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, dest)
|
||||
case "phone":
|
||||
@@ -124,8 +134,10 @@ func (c *ApiController) SendVerificationCode() {
|
||||
c.ResponseError(c.T("PhoneErr.NumberInvalid"))
|
||||
return
|
||||
}
|
||||
if organization == nil {
|
||||
c.ResponseError(c.T("OrgErr.DoNotExist"))
|
||||
|
||||
userByPhone := object.GetUserByPhone(organization.Name, dest)
|
||||
if userByPhone == nil {
|
||||
c.ResponseError(c.T("UserErr.DoNotExistSignUp"))
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -104,6 +104,11 @@ func (c *ApiController) WebAuthnSigninBegin() {
|
||||
c.ResponseError(fmt.Sprintf(c.T("UserErr.DoNotExistInOrg"), userOwner, userName))
|
||||
return
|
||||
}
|
||||
if len(user.WebauthnCredentials) == 0 {
|
||||
c.ResponseError(c.T("UserErr.NoWebAuthnCredential"))
|
||||
return
|
||||
}
|
||||
|
||||
options, sessionData, err := webauthnObj.BeginLogin(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
@@ -83,7 +83,7 @@ func parseToData() *I18nData {
|
||||
|
||||
data := I18nData{}
|
||||
for _, word := range allWords {
|
||||
tokens := strings.Split(word, ":")
|
||||
tokens := strings.SplitN(word, ":", 2)
|
||||
namespace := tokens[0]
|
||||
key := tokens[1]
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -134,4 +134,5 @@ NameTooLang = Username is too long (maximum is 39 characters).
|
||||
NameFormatErr = 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.
|
||||
PasswordLessThanSixCharacters = Password must have at least 6 characters
|
||||
InvalidInformation = Invalid information
|
||||
NoWebAuthnCredential = Found no credentials for this user
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
[ApplicationErr]
|
||||
AppNotFound = 应用 %%s 未找到
|
||||
AppNotFound = 应用 %s 未找到
|
||||
AppNotFoundForUserID = 找不到该用户的应用程序 %s
|
||||
GrantTypeNotSupport = 此应用中不支持此授权类型
|
||||
HasNoProviders = 该应用无提供商
|
||||
@@ -25,7 +25,7 @@ EmptyErr = 邮箱不可为空
|
||||
EmailInvalid = 无效邮箱
|
||||
EmailCheckResult = Email: %s
|
||||
EmptyParam = 邮件参数为空: %v
|
||||
InvalidReceivers = 无效的邮箱接收者: %%s
|
||||
InvalidReceivers = 无效的邮箱接收者: %s
|
||||
UnableGetModifyRule = 无法得到Email修改规则
|
||||
|
||||
[EnforcerErr]
|
||||
@@ -131,6 +131,7 @@ NameFormatErr = 用户名只能包含字母数字字符、下划线或连字符
|
||||
PasswordLessThanSixCharacters = 密码至少为6字符
|
||||
DoNotExistSignUp = 用户不存在,请先注册
|
||||
InvalidInformation = 无效信息
|
||||
NoWebAuthnCredential = 该用户没有WebAuthn凭据
|
||||
|
||||
[StorageErr]
|
||||
ObjectKeyNotAllowed = object key :%s 不被允许
|
||||
|
@@ -60,7 +60,7 @@ func getPermanentAvatarUrl(organization string, username string, url string, upl
|
||||
}
|
||||
|
||||
fullFilePath := fmt.Sprintf("/avatar/%s/%s.png", organization, username)
|
||||
uploadedFileUrl, _ := getUploadFileUrl(defaultStorageProvider, fullFilePath, false)
|
||||
uploadedFileUrl, _ := GetUploadFileUrl(defaultStorageProvider, fullFilePath, false)
|
||||
|
||||
if upload {
|
||||
DownloadAndUpload(url, fullFilePath)
|
||||
|
@@ -148,34 +148,7 @@ func (casbinAdapter *CasbinAdapter) getTable() string {
|
||||
}
|
||||
}
|
||||
|
||||
func safeReturn(policy []string, i int) string {
|
||||
if len(policy) > i {
|
||||
return policy[i]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func matrixToCasbinRules(pType string, policies [][]string) []*xormadapter.CasbinRule {
|
||||
res := []*xormadapter.CasbinRule{}
|
||||
|
||||
for _, policy := range policies {
|
||||
line := xormadapter.CasbinRule{
|
||||
Ptype: pType,
|
||||
V0: safeReturn(policy, 0),
|
||||
V1: safeReturn(policy, 1),
|
||||
V2: safeReturn(policy, 2),
|
||||
V3: safeReturn(policy, 3),
|
||||
V4: safeReturn(policy, 4),
|
||||
V5: safeReturn(policy, 5),
|
||||
}
|
||||
res = append(res, &line)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func SyncPolicies(casbinAdapter *CasbinAdapter) []*xormadapter.CasbinRule {
|
||||
func initEnforcer(modelObj *Model, casbinAdapter *CasbinAdapter) (*casbin.Enforcer, error) {
|
||||
// init Adapter
|
||||
if casbinAdapter.Adapter == nil {
|
||||
var dataSourceName string
|
||||
@@ -191,20 +164,60 @@ func SyncPolicies(casbinAdapter *CasbinAdapter) []*xormadapter.CasbinRule {
|
||||
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
||||
}
|
||||
|
||||
casbinAdapter.Adapter, _ = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(casbinAdapter.DatabaseType, dataSourceName, casbinAdapter.Database).Engine, casbinAdapter.getTable(), "")
|
||||
var err error
|
||||
casbinAdapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(casbinAdapter.DatabaseType, dataSourceName, casbinAdapter.Database).Engine, casbinAdapter.getTable(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// init Model
|
||||
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||
m, err := model.NewModelFromString(modelObj.ModelText)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init Enforcer
|
||||
enforcer, err := casbin.NewEnforcer(m, casbinAdapter.Adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return enforcer, nil
|
||||
}
|
||||
|
||||
func safeReturn(policy []string, i int) string {
|
||||
if len(policy) > i {
|
||||
return policy[i]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func matrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
|
||||
res := []*xormadapter.CasbinRule{}
|
||||
|
||||
for _, policy := range policies {
|
||||
line := xormadapter.CasbinRule{
|
||||
Ptype: Ptype,
|
||||
V0: safeReturn(policy, 0),
|
||||
V1: safeReturn(policy, 1),
|
||||
V2: safeReturn(policy, 2),
|
||||
V3: safeReturn(policy, 3),
|
||||
V4: safeReturn(policy, 4),
|
||||
V5: safeReturn(policy, 5),
|
||||
}
|
||||
res = append(res, &line)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func SyncPolicies(casbinAdapter *CasbinAdapter) ([]*xormadapter.CasbinRule, error) {
|
||||
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||
enforcer, err := initEnforcer(modelObj, casbinAdapter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
policies := matrixToCasbinRules("p", enforcer.GetPolicy())
|
||||
@@ -212,5 +225,48 @@ func SyncPolicies(casbinAdapter *CasbinAdapter) []*xormadapter.CasbinRule {
|
||||
policies = append(policies, matrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
|
||||
}
|
||||
|
||||
return policies
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func UpdatePolicy(oldPolicy, newPolicy []string, casbinAdapter *CasbinAdapter) (bool, error) {
|
||||
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||
enforcer, err := initEnforcer(modelObj, casbinAdapter)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := enforcer.UpdatePolicy(oldPolicy, newPolicy)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
func AddPolicy(policy []string, casbinAdapter *CasbinAdapter) (bool, error) {
|
||||
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||
enforcer, err := initEnforcer(modelObj, casbinAdapter)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := enforcer.AddPolicy(policy)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
func RemovePolicy(policy []string, casbinAdapter *CasbinAdapter) (bool, error) {
|
||||
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||
enforcer, err := initEnforcer(modelObj, casbinAdapter)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := enforcer.RemovePolicy(policy)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
|
||||
return affected, nil
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@ func escapePath(path string) string {
|
||||
return res
|
||||
}
|
||||
|
||||
func getUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
|
||||
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
|
||||
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
|
||||
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
|
||||
|
||||
@@ -93,7 +93,7 @@ func uploadFile(provider *Provider, fullFilePath string, fileBuffer *bytes.Buffe
|
||||
UpdateProvider(provider.GetId(), provider)
|
||||
}
|
||||
|
||||
fileUrl, objectKey := getUploadFileUrl(provider, fullFilePath, true)
|
||||
fileUrl, objectKey := GetUploadFileUrl(provider, fullFilePath, true)
|
||||
|
||||
_, err := storageProvider.Put(objectKey, fileBuffer)
|
||||
if err != nil {
|
||||
|
@@ -82,6 +82,7 @@ func initAPI() {
|
||||
|
||||
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
|
||||
beego.Router("/api/get-permissions-by-submitter", &controllers.ApiController{}, "GET:GetPermissionsBySubmitter")
|
||||
beego.Router("/api/get-permissions-by-role", &controllers.ApiController{}, "GET:GetPermissionsByRole")
|
||||
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission")
|
||||
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
|
||||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
||||
@@ -105,6 +106,9 @@ func initAPI() {
|
||||
beego.Router("/api/add-adapter", &controllers.ApiController{}, "POST:AddCasbinAdapter")
|
||||
beego.Router("/api/delete-adapter", &controllers.ApiController{}, "POST:DeleteCasbinAdapter")
|
||||
beego.Router("/api/sync-policies", &controllers.ApiController{}, "GET:SyncPolicies")
|
||||
beego.Router("/api/update-policy", &controllers.ApiController{}, "POST:UpdatePolicy")
|
||||
beego.Router("/api/add-policy", &controllers.ApiController{}, "POST:AddPolicy")
|
||||
beego.Router("/api/remove-policy", &controllers.ApiController{}, "POST:RemovePolicy")
|
||||
|
||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||
|
29
util/struct.go
Normal file
29
util/struct.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
|
||||
import xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||
|
||||
func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
|
||||
s := []string{
|
||||
casbinRule.V0,
|
||||
casbinRule.V1,
|
||||
casbinRule.V2,
|
||||
casbinRule.V3,
|
||||
casbinRule.V4,
|
||||
casbinRule.V5,
|
||||
}
|
||||
return s
|
||||
}
|
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch, Table, Tooltip} from "antd";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
||||
import * as AdapterBackend from "./backend/AdapterBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as Setting from "./Setting";
|
||||
@@ -21,7 +21,7 @@ import i18next from "i18next";
|
||||
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import * as ModelBackend from "./backend/ModelBackend";
|
||||
import {EditOutlined, MinusOutlined} from "@ant-design/icons";
|
||||
import PolicyTable from "./common/PoliciyTable";
|
||||
require("codemirror/theme/material-darker.css");
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
@@ -32,12 +32,11 @@ class AdapterEditPage extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
owner: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
adapterName: props.match.params.adapterName,
|
||||
adapter: null,
|
||||
organizations: [],
|
||||
models: [],
|
||||
policyLists: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
@@ -48,7 +47,7 @@ class AdapterEditPage extends React.Component {
|
||||
}
|
||||
|
||||
getAdapter() {
|
||||
AdapterBackend.getAdapter(this.state.organizationName, this.state.adapterName)
|
||||
AdapterBackend.getAdapter(this.state.owner, this.state.adapterName)
|
||||
.then((adapter) => {
|
||||
this.setState({
|
||||
adapter: adapter,
|
||||
@@ -93,93 +92,6 @@ class AdapterEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
synPolicies() {
|
||||
this.setState({loading: true});
|
||||
AdapterBackend.syncPolicies(this.state.adapter.owner, this.state.adapter.name)
|
||||
.then((res) => {
|
||||
this.setState({loading: false, policyLists: res});
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({loading: false});
|
||||
Setting.showMessage("error", `Adapter failed to get policies: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(table) {
|
||||
const columns = [
|
||||
{
|
||||
title: "Rule Type",
|
||||
dataIndex: "PType",
|
||||
key: "PType",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V0",
|
||||
dataIndex: "V0",
|
||||
key: "V0",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V1",
|
||||
dataIndex: "V1",
|
||||
key: "V1",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V2",
|
||||
dataIndex: "V2",
|
||||
key: "V2",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V3",
|
||||
dataIndex: "V3",
|
||||
key: "V3",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V4",
|
||||
dataIndex: "V4",
|
||||
key: "V4",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "V5",
|
||||
dataIndex: "V5",
|
||||
key: "V5",
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
title: "Option",
|
||||
key: "option",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Tooltip placement="topLeft" title="Edit">
|
||||
<Button style={{marginRight: "0.5rem"}} icon={<EditOutlined />} size="small" />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Delete">
|
||||
<Button icon={<MinusOutlined />} size="small" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
pagination={{
|
||||
defaultPageSize: 10,
|
||||
}}
|
||||
columns={columns} dataSource={table} rowKey="name" size="middle" bordered
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderAdapter() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
@@ -329,19 +241,8 @@ class AdapterEditPage extends React.Component {
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("adapter:Policies"), i18next.t("adapter:Policies - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={2}>
|
||||
<Button type="primary" onClick={() => {this.synPolicies();}}>
|
||||
{i18next.t("adapter:Sync")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
{
|
||||
this.renderTable(this.state.policyLists)
|
||||
}
|
||||
<Col span={22}>
|
||||
<PolicyTable owner={this.state.owner} name={this.state.adapterName} mode={this.state.mode} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
@@ -362,8 +263,8 @@ class AdapterEditPage extends React.Component {
|
||||
const adapter = Setting.deepCopy(this.state.adapter);
|
||||
AdapterBackend.updateAdapter(this.state.adapter.owner, this.state.adapterName, adapter)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
adapterName: this.state.adapter.name,
|
||||
});
|
||||
@@ -371,25 +272,29 @@ class AdapterEditPage extends React.Component {
|
||||
if (willExist) {
|
||||
this.props.history.push("/adapters");
|
||||
} else {
|
||||
this.props.history.push(`/adapters/${this.state.adapter.name}`);
|
||||
this.props.history.push(`/adapters/${this.state.owner}/${this.state.adapter.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateAdapterField("name", this.state.adapterName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteAdapter() {
|
||||
AdapterBackend.deleteAdapter(this.state.adapter)
|
||||
.then(() => {
|
||||
this.props.history.push("/adapters");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/adapters");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `adapter failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -45,26 +45,33 @@ class AdapterListPage extends BaseListPage {
|
||||
const newAdapter = this.newAdapter();
|
||||
AdapterBackend.addAdapter(newAdapter)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/adapters/${newAdapter.owner}/${newAdapter.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/adapters/${newAdapter.organization}/${newAdapter.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Adapter failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteAdapter(i) {
|
||||
AdapterBackend.deleteAdapter(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Adapter deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Adapter failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -49,6 +49,9 @@ const template = `<style>
|
||||
}
|
||||
</style>`;
|
||||
|
||||
const previewGrid = Setting.isMobile() ? 22 : 11;
|
||||
const previewWidth = Setting.isMobile() ? "110%" : "90%";
|
||||
|
||||
const sideTemplate = `<style>
|
||||
.left-model{
|
||||
text-align: center;
|
||||
@@ -188,7 +191,7 @@ class ApplicationEditPage extends React.Component {
|
||||
Setting.showMessage("success", i18next.t("application:File uploaded successfully"));
|
||||
this.updateApplicationField("termsOfUse", res.data);
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setState({uploading: false});
|
||||
@@ -720,7 +723,7 @@ class ApplicationEditPage extends React.Component {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Col span={11}>
|
||||
<Col span={previewGrid}>
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
copy(`${window.location.origin}${signUpUrl}`);
|
||||
Setting.showMessage("success", i18next.t("application:Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
|
||||
@@ -729,7 +732,7 @@ class ApplicationEditPage extends React.Component {
|
||||
{i18next.t("application:Copy signup page URL")}
|
||||
</Button>
|
||||
<br />
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
{
|
||||
this.state.application.enablePassword ? (
|
||||
<SignupPage application={this.state.application} />
|
||||
@@ -740,8 +743,8 @@ class ApplicationEditPage extends React.Component {
|
||||
<div style={maskStyle} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
<Col span={previewGrid}>
|
||||
<Button style={{marginBottom: "10px", marginTop: Setting.isMobile() ? "15px" : "0"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
copy(`${window.location.origin}${signInUrl}`);
|
||||
Setting.showMessage("success", i18next.t("application:Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
|
||||
}}
|
||||
@@ -749,7 +752,7 @@ class ApplicationEditPage extends React.Component {
|
||||
{i18next.t("application:Copy signin page URL")}
|
||||
</Button>
|
||||
<br />
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
|
||||
<div style={maskStyle} />
|
||||
</div>
|
||||
@@ -762,7 +765,7 @@ class ApplicationEditPage extends React.Component {
|
||||
const promptUrl = `/prompt/${this.state.application.name}`;
|
||||
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||
return (
|
||||
<Col span={11}>
|
||||
<Col span={previewGrid}>
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
copy(`${window.location.origin}${promptUrl}`);
|
||||
Setting.showMessage("success", i18next.t("application:Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser"));
|
||||
@@ -771,7 +774,7 @@ class ApplicationEditPage extends React.Component {
|
||||
{i18next.t("application:Copy prompt page URL")}
|
||||
</Button>
|
||||
<br />
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", flexDirection: "column", flex: "auto"}}>
|
||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", flexDirection: "column", flex: "auto"}}>
|
||||
<PromptPage application={this.state.application} account={this.props.account} />
|
||||
<div style={maskStyle} />
|
||||
</div>
|
||||
@@ -783,8 +786,8 @@ class ApplicationEditPage extends React.Component {
|
||||
const application = Setting.deepCopy(this.state.application);
|
||||
ApplicationBackend.updateApplication("admin", this.state.applicationName, application)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
applicationName: this.state.application.name,
|
||||
});
|
||||
@@ -795,22 +798,26 @@ class ApplicationEditPage extends React.Component {
|
||||
this.props.history.push(`/applications/${this.state.application.organization}/${this.state.application.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateApplicationField("name", this.state.applicationName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteApplication() {
|
||||
ApplicationBackend.deleteApplication(this.state.application)
|
||||
.then(() => {
|
||||
this.props.history.push("/applications");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/applications");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Application failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -78,26 +78,33 @@ class ApplicationListPage extends BaseListPage {
|
||||
const newApplication = this.newApplication();
|
||||
ApplicationBackend.addApplication(newApplication)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/applications/${newApplication.organization}/${newApplication.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/applications/${newApplication.organization}/${newApplication.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Application failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteApplication(i) {
|
||||
ApplicationBackend.deleteApplication(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Application deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Application failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -217,8 +217,8 @@ class CertEditPage extends React.Component {
|
||||
const cert = Setting.deepCopy(this.state.cert);
|
||||
CertBackend.updateCert(this.state.cert.owner, this.state.certName, cert)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
certName: this.state.cert.name,
|
||||
});
|
||||
@@ -229,22 +229,26 @@ class CertEditPage extends React.Component {
|
||||
this.props.history.push(`/certs/${this.state.cert.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateCertField("name", this.state.certName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteCert() {
|
||||
CertBackend.deleteCert(this.state.cert)
|
||||
.then(() => {
|
||||
this.props.history.push("/certs");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/certs");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -43,26 +43,33 @@ class CertListPage extends BaseListPage {
|
||||
const newCert = this.newCert();
|
||||
CertBackend.addCert(newCert)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteCert(i) {
|
||||
CertBackend.deleteCert(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Cert deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -81,7 +81,7 @@ class LdapTable extends React.Component {
|
||||
table = Setting.deleteRow(table, i);
|
||||
this.updateTable(table);
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@@ -158,8 +158,8 @@ class ModelEditPage extends React.Component {
|
||||
const model = Setting.deepCopy(this.state.model);
|
||||
ModelBackend.updateModel(this.state.organizationName, this.state.modelName, model)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
modelName: this.state.model.name,
|
||||
});
|
||||
@@ -170,22 +170,26 @@ class ModelEditPage extends React.Component {
|
||||
this.props.history.push(`/models/${this.state.model.owner}/${this.state.model.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateModelField("name", this.state.modelName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteModel() {
|
||||
ModelBackend.deleteModel(this.state.model)
|
||||
.then(() => {
|
||||
this.props.history.push("/models");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/models");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Model failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -38,26 +38,33 @@ class ModelListPage extends BaseListPage {
|
||||
const newModel = this.newModel();
|
||||
ModelBackend.addModel(newModel)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/models/${newModel.owner}/${newModel.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/models/${newModel.owner}/${newModel.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Model failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteModel(i) {
|
||||
ModelBackend.deleteModel(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Model deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Model failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -335,8 +335,8 @@ class OrganizationEditPage extends React.Component {
|
||||
const organization = Setting.deepCopy(this.state.organization);
|
||||
OrganizationBackend.updateOrganization(this.state.organization.owner, this.state.organizationName, organization)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
organizationName: this.state.organization.name,
|
||||
});
|
||||
@@ -347,22 +347,26 @@ class OrganizationEditPage extends React.Component {
|
||||
this.props.history.push(`/organizations/${this.state.organization.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateOrganizationField("name", this.state.organizationName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteOrganization() {
|
||||
OrganizationBackend.deleteOrganization(this.state.organization)
|
||||
.then(() => {
|
||||
this.props.history.push("/organizations");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/organizations");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -75,26 +75,33 @@ class OrganizationListPage extends BaseListPage {
|
||||
const newOrganization = this.newOrganization();
|
||||
OrganizationBackend.addOrganization(newOrganization)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Organization failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteOrganization(i) {
|
||||
OrganizationBackend.deleteOrganization(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Organization deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Organization failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -78,7 +78,7 @@ class PaymentEditPage extends React.Component {
|
||||
this.setState({
|
||||
isInvoiceLoading: false,
|
||||
});
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", "Successfully invoiced");
|
||||
Setting.openLinkSafe(res.data);
|
||||
this.getPayment();
|
||||
@@ -90,7 +90,7 @@ class PaymentEditPage extends React.Component {
|
||||
this.setState({
|
||||
isInvoiceLoading: false,
|
||||
});
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -443,8 +443,8 @@ class PaymentEditPage extends React.Component {
|
||||
const payment = Setting.deepCopy(this.state.payment);
|
||||
PaymentBackend.updatePayment(this.state.payment.owner, this.state.paymentName, payment)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
paymentName: this.state.payment.name,
|
||||
});
|
||||
@@ -455,22 +455,26 @@ class PaymentEditPage extends React.Component {
|
||||
this.props.history.push(`/payments/${this.state.payment.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updatePaymentField("name", this.state.paymentName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deletePayment() {
|
||||
PaymentBackend.deletePayment(this.state.payment)
|
||||
.then(() => {
|
||||
this.props.history.push("/payments");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/payments");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Payment failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -51,26 +51,34 @@ class PaymentListPage extends BaseListPage {
|
||||
const newPayment = this.newPayment();
|
||||
PaymentBackend.addPayment(newPayment)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Payment failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deletePayment(i) {
|
||||
PaymentBackend.deletePayment(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Payment deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Payment failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -417,8 +417,8 @@ class PermissionEditPage extends React.Component {
|
||||
const permission = Setting.deepCopy(this.state.permission);
|
||||
PermissionBackend.updatePermission(this.state.organizationName, this.state.permissionName, permission)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
permissionName: this.state.permission.name,
|
||||
});
|
||||
@@ -429,22 +429,26 @@ class PermissionEditPage extends React.Component {
|
||||
this.props.history.push(`/permissions/${this.state.permission.owner}/${this.state.permission.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updatePermissionField("name", this.state.permissionName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deletePermission() {
|
||||
PermissionBackend.deletePermission(this.state.permission)
|
||||
.then(() => {
|
||||
this.props.history.push("/permissions");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/permissions");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -48,30 +48,33 @@ class PermissionListPage extends BaseListPage {
|
||||
const newPermission = this.newPermission();
|
||||
PermissionBackend.addPermission(newPermission)
|
||||
.then((res) => {
|
||||
if (res.msg !== "") {
|
||||
Setting.showMessage("error", res.msg);
|
||||
return;
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deletePermission(i) {
|
||||
PermissionBackend.deletePermission(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Permission deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -81,11 +81,11 @@ class ProductBuyPage extends React.Component {
|
||||
|
||||
ProductBackend.buyProduct(this.state.product.owner, this.state.productName, provider.name)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
const payUrl = res.data;
|
||||
Setting.goToLink(payUrl);
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
|
||||
this.setState({
|
||||
isPlacingOrder: false,
|
||||
@@ -93,7 +93,7 @@ class ProductBuyPage extends React.Component {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -271,8 +271,8 @@ class ProductEditPage extends React.Component {
|
||||
const product = Setting.deepCopy(this.state.product);
|
||||
ProductBackend.updateProduct(this.state.product.owner, this.state.productName, product)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
productName: this.state.product.name,
|
||||
});
|
||||
@@ -283,22 +283,26 @@ class ProductEditPage extends React.Component {
|
||||
this.props.history.push(`/products/${this.state.product.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateProductField("name", this.state.productName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProduct() {
|
||||
ProductBackend.deleteProduct(this.state.product)
|
||||
.then(() => {
|
||||
this.props.history.push("/products");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/products");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -45,26 +45,33 @@ class ProductListPage extends BaseListPage {
|
||||
const newProduct = this.newProduct();
|
||||
ProductBackend.addProduct(newProduct)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProduct(i) {
|
||||
ProductBackend.deleteProduct(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Product deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Product failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -257,7 +257,9 @@ class ProviderEditPage extends React.Component {
|
||||
{id: "SAML", name: "SAML"},
|
||||
{id: "Payment", name: "Payment"},
|
||||
{id: "Captcha", name: "Captcha"},
|
||||
].map((providerCategory, index) => <Option key={index} value={providerCategory.id}>{providerCategory.name}</Option>)
|
||||
]
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((providerCategory, index) => <Option key={index} value={providerCategory.id}>{providerCategory.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
@@ -280,7 +282,9 @@ class ProviderEditPage extends React.Component {
|
||||
}
|
||||
})}>
|
||||
{
|
||||
Setting.getProviderTypeOptions(this.state.provider.category).map((providerType, index) => <Option key={index} value={providerType.id}>{providerType.name}</Option>)
|
||||
Setting.getProviderTypeOptions(this.state.provider.category)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((providerType, index) => <Option key={index} value={providerType.id}>{providerType.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
@@ -789,8 +793,8 @@ class ProviderEditPage extends React.Component {
|
||||
const provider = Setting.deepCopy(this.state.provider);
|
||||
ProviderBackend.updateProvider(this.state.owner, this.state.providerName, provider)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
owner: this.state.provider.owner,
|
||||
providerName: this.state.provider.name,
|
||||
@@ -802,22 +806,26 @@ class ProviderEditPage extends React.Component {
|
||||
this.props.history.push(`/providers/${this.state.provider.owner}/${this.state.provider.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateProviderField("name", this.state.providerName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProvider() {
|
||||
ProviderBackend.deleteProvider(this.state.provider)
|
||||
.then(() => {
|
||||
this.props.history.push("/providers");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/providers");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Provider failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -61,26 +61,33 @@ class ProviderListPage extends BaseListPage {
|
||||
const newProvider = this.newProvider();
|
||||
ProviderBackend.addProvider(newProvider)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/providers/${newProvider.owner}/${newProvider.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/providers/${newProvider.owner}/${newProvider.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Provider failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteProvider(i) {
|
||||
ProviderBackend.deleteProvider(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Provider deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Provider failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -43,15 +43,18 @@ class ResourceListPage extends BaseListPage {
|
||||
deleteResource(i) {
|
||||
ResourceBackend.deleteResource(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Resource deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Resource failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -196,8 +196,8 @@ class RoleEditPage extends React.Component {
|
||||
const role = Setting.deepCopy(this.state.role);
|
||||
RoleBackend.updateRole(this.state.organizationName, this.state.roleName, role)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
roleName: this.state.role.name,
|
||||
});
|
||||
@@ -208,22 +208,26 @@ class RoleEditPage extends React.Component {
|
||||
this.props.history.push(`/roles/${this.state.role.owner}/${this.state.role.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateRoleField("name", this.state.roleName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteRole() {
|
||||
RoleBackend.deleteRole(this.state.role)
|
||||
.then(() => {
|
||||
this.props.history.push("/roles");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/roles");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -40,26 +40,33 @@ class RoleListPage extends BaseListPage {
|
||||
const newRole = this.newRole();
|
||||
RoleBackend.addRole(newRole)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/roles/${newRole.owner}/${newRole.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/roles/${newRole.owner}/${newRole.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteRole(i) {
|
||||
RoleBackend.deleteRole(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Role deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to delete: ${error}`);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -145,6 +145,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_geetest.png`,
|
||||
url: "https://www.geetest.com",
|
||||
},
|
||||
"Cloudflare Turnstile": {
|
||||
logo: `${StaticBaseUrl}/img/social_cloudflare.png`,
|
||||
url: "https://www.cloudflare.com/products/turnstile/",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -416,9 +420,7 @@ export function goToLinkSoft(ths, link) {
|
||||
}
|
||||
|
||||
export function showMessage(type, text) {
|
||||
if (type === "") {
|
||||
return;
|
||||
} else if (type === "success") {
|
||||
if (type === "success") {
|
||||
message.success(text);
|
||||
} else if (type === "error") {
|
||||
message.error(text);
|
||||
@@ -445,8 +447,8 @@ export function deepCopy(obj) {
|
||||
return Object.assign({}, obj);
|
||||
}
|
||||
|
||||
export function addRow(array, row) {
|
||||
return [...array, row];
|
||||
export function addRow(array, row, position = "end") {
|
||||
return position === "end" ? [...array, row] : [row, ...array];
|
||||
}
|
||||
|
||||
export function prependRow(array, row) {
|
||||
@@ -697,6 +699,7 @@ export function getProviderTypeOptions(category) {
|
||||
{id: "hCaptcha", name: "hCaptcha"},
|
||||
{id: "Aliyun Captcha", name: "Aliyun Captcha"},
|
||||
{id: "GEETEST", name: "GEETEST"},
|
||||
{id: "Cloudflare Turnstile", name: "Cloudflare Turnstile"},
|
||||
]);
|
||||
} else {
|
||||
return [];
|
||||
|
@@ -298,8 +298,8 @@ class SyncerEditPage extends React.Component {
|
||||
const syncer = Setting.deepCopy(this.state.syncer);
|
||||
SyncerBackend.updateSyncer(this.state.syncer.owner, this.state.syncerName, syncer)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
syncerName: this.state.syncer.name,
|
||||
});
|
||||
@@ -310,22 +310,26 @@ class SyncerEditPage extends React.Component {
|
||||
this.props.history.push(`/syncers/${this.state.syncer.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateSyncerField("name", this.state.syncerName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteSyncer() {
|
||||
SyncerBackend.deleteSyncer(this.state.syncer)
|
||||
.then(() => {
|
||||
this.props.history.push("/syncers");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/syncers");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Syncer failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -49,26 +49,33 @@ class SyncerListPage extends BaseListPage {
|
||||
const newSyncer = this.newSyncer();
|
||||
SyncerBackend.addSyncer(newSyncer)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/syncers/${newSyncer.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/syncers/${newSyncer.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Syncer failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteSyncer(i) {
|
||||
SyncerBackend.deleteSyncer(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Syncer deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Syncer failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -13,32 +13,33 @@
|
||||
// limitations under the License.
|
||||
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export function sendTestEmail(provider, email) {
|
||||
testEmailProvider(provider, email)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", "Successfully send email");
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
export function connectSmtpServer(provider) {
|
||||
testEmailProvider(provider)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", "Successfully connecting smtp server");
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -167,8 +167,8 @@ class TokenEditPage extends React.Component {
|
||||
const token = Setting.deepCopy(this.state.token);
|
||||
TokenBackend.updateToken(this.state.token.owner, this.state.tokenName, token)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
tokenName: this.state.token.name,
|
||||
});
|
||||
@@ -179,22 +179,26 @@ class TokenEditPage extends React.Component {
|
||||
this.props.history.push(`/tokens/${this.state.token.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateTokenField("name", this.state.tokenName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteToken() {
|
||||
TokenBackend.deleteToken(this.state.token)
|
||||
.then(() => {
|
||||
this.props.history.push("/tokens");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/tokens");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Token failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -42,26 +42,33 @@ class TokenListPage extends BaseListPage {
|
||||
const newToken = this.newToken();
|
||||
TokenBackend.addToken(newToken)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/tokens/${newToken.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/tokens/${newToken.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Token failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteToken(i) {
|
||||
TokenBackend.deleteToken(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Token deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Token failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -49,6 +49,7 @@ class UserEditPage extends React.Component {
|
||||
applications: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
loading: true,
|
||||
returnUrl: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,6 +58,7 @@ class UserEditPage extends React.Component {
|
||||
this.getOrganizations();
|
||||
this.getApplicationsByOrganization(this.state.organizationName);
|
||||
this.getUserApplication();
|
||||
this.setReturnUrl();
|
||||
}
|
||||
|
||||
getUser() {
|
||||
@@ -100,9 +102,14 @@ class UserEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getReturnUrl() {
|
||||
setReturnUrl() {
|
||||
const searchParams = new URLSearchParams(this.props.location.search);
|
||||
return searchParams.get("returnUrl");
|
||||
const returnUrl = searchParams.get("returnUrl");
|
||||
if (returnUrl !== null) {
|
||||
this.setState({
|
||||
returnUrl: returnUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
parseUserField(key, value) {
|
||||
@@ -604,8 +611,8 @@ class UserEditPage extends React.Component {
|
||||
const user = Setting.deepCopy(this.state.user);
|
||||
UserBackend.updateUser(this.state.organizationName, this.state.userName, user)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
organizationName: this.state.user.owner,
|
||||
userName: this.state.user.name,
|
||||
@@ -619,30 +626,33 @@ class UserEditPage extends React.Component {
|
||||
}
|
||||
} else {
|
||||
if (willExist) {
|
||||
const returnUrl = this.getReturnUrl();
|
||||
if (returnUrl) {
|
||||
window.location.href = returnUrl;
|
||||
if (this.state.returnUrl) {
|
||||
window.location.href = this.state.returnUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateUserField("owner", this.state.organizationName);
|
||||
this.updateUserField("name", this.state.userName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteUser() {
|
||||
UserBackend.deleteUser(this.state.user)
|
||||
.then(() => {
|
||||
this.props.history.push("/users");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/users");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `User failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -72,26 +72,33 @@ class UserListPage extends BaseListPage {
|
||||
const newUser = this.newUser();
|
||||
UserBackend.addUser(newUser)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `User failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteUser(i) {
|
||||
UserBackend.deleteUser(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "User deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `User failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ class WebAuthnCredentialTable extends React.Component {
|
||||
|
||||
registerWebAuthn() {
|
||||
UserWebauthnBackend.registerWebauthnCredential().then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", "Successfully added webauthn credentials");
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
@@ -34,7 +34,7 @@ class WebAuthnCredentialTable extends React.Component {
|
||||
|
||||
this.props.refresh();
|
||||
}).catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -296,8 +296,8 @@ class WebhookEditPage extends React.Component {
|
||||
const webhook = Setting.deepCopy(this.state.webhook);
|
||||
WebhookBackend.updateWebhook(this.state.webhook.owner, this.state.webhookName, webhook)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
webhookName: this.state.webhook.name,
|
||||
});
|
||||
@@ -308,22 +308,26 @@ class WebhookEditPage extends React.Component {
|
||||
this.props.history.push(`/webhooks/${this.state.webhook.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updateWebhookField("name", this.state.webhookName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteWebhook() {
|
||||
WebhookBackend.deleteWebhook(this.state.webhook)
|
||||
.then(() => {
|
||||
this.props.history.push("/webhooks");
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/webhooks");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Webhook failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -42,26 +42,33 @@ class WebhookListPage extends BaseListPage {
|
||||
const newWebhook = this.newWebhook();
|
||||
WebhookBackend.addWebhook(newWebhook)
|
||||
.then((res) => {
|
||||
this.props.history.push({pathname: `/webhooks/${newWebhook.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/webhooks/${newWebhook.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Webhook failed to add: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteWebhook(i) {
|
||||
WebhookBackend.deleteWebhook(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", "Webhook deleted successfully");
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Webhook failed to delete: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -126,7 +126,7 @@ class AuthCallback extends React.Component {
|
||||
// If service was not specified, Casdoor must display a message notifying the client that it has successfully initiated a single sign-on session.
|
||||
msg += "Now you can visit apps protected by Casdoor.";
|
||||
}
|
||||
Util.showMessage("success", msg);
|
||||
Setting.showMessage("success", msg);
|
||||
|
||||
if (casService !== "") {
|
||||
const st = res.data;
|
||||
@@ -135,7 +135,7 @@ class AuthCallback extends React.Component {
|
||||
window.location.href = newUrl.toString();
|
||||
}
|
||||
} else {
|
||||
Util.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
Setting.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
return;
|
||||
@@ -148,7 +148,7 @@ class AuthCallback extends React.Component {
|
||||
if (res.status === "ok") {
|
||||
const responseType = this.getResponseType();
|
||||
if (responseType === "login") {
|
||||
Util.showMessage("success", "Logged in successfully");
|
||||
Setting.showMessage("success", "Logged in successfully");
|
||||
// Setting.goToLinkSoft(this, "/");
|
||||
|
||||
const link = Setting.getFromLink();
|
||||
@@ -156,7 +156,7 @@ class AuthCallback extends React.Component {
|
||||
} else if (responseType === "code") {
|
||||
const code = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
|
||||
// Util.showMessage("success", `Authorization code: ${res.data}`);
|
||||
// Setting.showMessage("success", `Authorization code: ${res.data}`);
|
||||
} else if (responseType === "token" || responseType === "id_token") {
|
||||
const token = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`);
|
||||
|
@@ -61,10 +61,7 @@ class ForgetPage extends React.Component {
|
||||
if (this.state.applicationName !== undefined) {
|
||||
this.getApplication();
|
||||
} else {
|
||||
Util.showMessage(
|
||||
"error",
|
||||
i18next.t("forget:Unknown forget type: ") + this.state.type
|
||||
);
|
||||
Setting.showMessage("error", i18next.t("forget:Unknown forget type: ") + this.state.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -67,7 +67,7 @@ class LoginPage extends React.Component {
|
||||
} else if (this.state.type === "saml") {
|
||||
this.getSamlApplication();
|
||||
} else {
|
||||
Util.showMessage("error", `Unknown authentication type: ${this.state.type}`);
|
||||
Setting.showMessage("error", `Unknown authentication type: ${this.state.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class LoginPage extends React.Component {
|
||||
application: res.data,
|
||||
});
|
||||
} else {
|
||||
// Util.showMessage("error", res.msg);
|
||||
// Setting.showMessage("error", res.msg);
|
||||
this.setState({
|
||||
application: res.data,
|
||||
msg: res.msg,
|
||||
@@ -122,7 +122,7 @@ class LoginPage extends React.Component {
|
||||
applicationName: res.data.name,
|
||||
});
|
||||
} else {
|
||||
Util.showMessage("error", res.msg);
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -269,7 +269,7 @@ class LoginPage extends React.Component {
|
||||
// If service was not specified, Casdoor must display a message notifying the client that it has successfully initiated a single sign-on session.
|
||||
msg += "Now you can visit apps protected by Casdoor.";
|
||||
}
|
||||
Util.showMessage("success", msg);
|
||||
Setting.showMessage("success", msg);
|
||||
|
||||
this.setState({openCaptchaModal: false});
|
||||
|
||||
@@ -281,7 +281,7 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
} else {
|
||||
this.setState({openCaptchaModal: false});
|
||||
Util.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
Setting.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -295,13 +295,13 @@ class LoginPage extends React.Component {
|
||||
const responseType = values["type"];
|
||||
|
||||
if (responseType === "login") {
|
||||
Util.showMessage("success", "Logged in successfully");
|
||||
Setting.showMessage("success", "Logged in successfully");
|
||||
|
||||
const link = Setting.getFromLink();
|
||||
Setting.goToLink(link);
|
||||
} else if (responseType === "code") {
|
||||
this.postCodeLoginAction(res);
|
||||
// Util.showMessage("success", `Authorization code: ${res.data}`);
|
||||
// Setting.showMessage("success", `Authorization code: ${res.data}`);
|
||||
} else if (responseType === "token" || responseType === "id_token") {
|
||||
const accessToken = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`);
|
||||
@@ -312,7 +312,7 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
} else {
|
||||
this.setState({openCaptchaModal: false});
|
||||
Util.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
Setting.showMessage("error", `Failed to log in: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -335,8 +335,8 @@ class LoginPage extends React.Component {
|
||||
return (
|
||||
<Result
|
||||
status="error"
|
||||
title="Sign Up Error"
|
||||
subTitle={"The application does not allow to sign up new account"}
|
||||
title={i18next.t("application:Sign Up Error")}
|
||||
subTitle={i18next.t("application:The application does not allow to sign up new account")}
|
||||
extra={[
|
||||
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
|
||||
{
|
||||
@@ -368,7 +368,7 @@ class LoginPage extends React.Component {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "Please input your application!",
|
||||
message: i18next.t("application:Please input your application!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -379,7 +379,7 @@ class LoginPage extends React.Component {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "Please input your organization!",
|
||||
message: i18next.t("application:Please input your organization!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@@ -673,7 +673,7 @@ class LoginPage extends React.Component {
|
||||
}),
|
||||
})
|
||||
.then(res => res.json()).then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
const responseType = values["type"];
|
||||
if (responseType === "code") {
|
||||
this.postCodeLoginAction(res);
|
||||
@@ -681,7 +681,7 @@ class LoginPage extends React.Component {
|
||||
const accessToken = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`);
|
||||
} else {
|
||||
Setting.showMessage("success", "Successfully logged in with webauthn credentials");
|
||||
Setting.showMessage("success", i18next.t("login:Successfully logged in with webauthn credentials"));
|
||||
Setting.goToLink("/");
|
||||
}
|
||||
} else {
|
||||
@@ -689,7 +689,7 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}${error}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -203,9 +203,9 @@ class PromptPage extends React.Component {
|
||||
const user = Setting.deepCopy(this.state.user);
|
||||
UserBackend.updateUser(this.state.user.owner, this.state.user.name, user)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
if (res.status === "ok") {
|
||||
if (isFinal) {
|
||||
Setting.showMessage("success", "Successfully saved");
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
|
||||
this.logout();
|
||||
}
|
||||
@@ -217,7 +217,7 @@ class PromptPage extends React.Component {
|
||||
})
|
||||
.catch(error => {
|
||||
if (isFinal) {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -232,8 +232,8 @@ class PromptPage extends React.Component {
|
||||
return (
|
||||
<Result
|
||||
status="error"
|
||||
title="Sign Up Error"
|
||||
subTitle={"You are unexpected to see this prompt page"}
|
||||
title={i18next.t("application:Sign Up Error")}
|
||||
subTitle={i18next.t("application:You are unexpected to see this prompt page")}
|
||||
extra={[
|
||||
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
|
||||
{
|
||||
|
@@ -16,7 +16,6 @@ import React from "react";
|
||||
import {Button, Result} from "antd";
|
||||
import i18next from "i18next";
|
||||
import {authConfig} from "./Auth";
|
||||
import * as Util from "./Util";
|
||||
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
@@ -34,7 +33,7 @@ class ResultPage extends React.Component {
|
||||
if (this.state.applicationName !== undefined) {
|
||||
this.getApplication();
|
||||
} else {
|
||||
Util.showMessage("error", `Unknown application name: ${this.state.applicationName}`);
|
||||
Setting.showMessage("error", `Unknown application name: ${this.state.applicationName}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -79,7 +79,7 @@ class SamlCallback extends React.Component {
|
||||
if (res.status === "ok") {
|
||||
const responseType = this.getResponseType(redirectUri);
|
||||
if (responseType === "login") {
|
||||
Util.showMessage("success", "Logged in successfully");
|
||||
Setting.showMessage("success", "Logged in successfully");
|
||||
Setting.goToLink("/");
|
||||
} else if (responseType === "code") {
|
||||
const code = res.data;
|
||||
|
@@ -94,7 +94,7 @@ class SignupPage extends React.Component {
|
||||
if (applicationName !== undefined) {
|
||||
this.getApplication(applicationName);
|
||||
} else {
|
||||
Util.showMessage("error", `Unknown application name: ${applicationName}`);
|
||||
Setting.showMessage("error", `Unknown application name: ${applicationName}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,8 +539,8 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<Result
|
||||
status="error"
|
||||
title="Sign Up Error"
|
||||
subTitle={"The application does not allow to sign up new account"}
|
||||
title={i18next.t("application:Sign Up Error")}
|
||||
subTitle={i18next.t("application:The application does not allow to sign up new account")}
|
||||
extra={[
|
||||
<Button type="primary" key="signin" onClick={() => Setting.redirectToLoginPage(application, this.props.history)}>
|
||||
{
|
||||
|
@@ -13,19 +13,11 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Alert, Button, Result, message} from "antd";
|
||||
import {Alert, Button, Result} from "antd";
|
||||
import {getWechatMessageEvent} from "./AuthBackend";
|
||||
import * as Setting from "../Setting";
|
||||
import * as Provider from "./Provider";
|
||||
|
||||
export function showMessage(type, text) {
|
||||
if (type === "success") {
|
||||
message.success(text);
|
||||
} else if (type === "error") {
|
||||
message.error(text);
|
||||
}
|
||||
}
|
||||
|
||||
export function renderMessage(msg) {
|
||||
if (msg !== null) {
|
||||
return (
|
||||
|
@@ -70,6 +70,41 @@ export function deleteAdapter(Adapter) {
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function UpdatePolicy(owner, name, policy) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(policy);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-policy?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(policy),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function AddPolicy(owner, name, policy) {
|
||||
return fetch(`${Setting.ServerUrl}/api/add-policy?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(policy),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function RemovePolicy(owner, name, policy) {
|
||||
return fetch(`${Setting.ServerUrl}/api/remove-policy?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(policy),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function syncPolicies(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/sync-policies?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
|
@@ -105,6 +105,21 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
|
||||
}, 500);
|
||||
break;
|
||||
}
|
||||
case "Cloudflare Turnstile": {
|
||||
const tTimer = setInterval(() => {
|
||||
if (!window.turnstile) {
|
||||
loadScript("https://challenges.cloudflare.com/turnstile/v0/api.js");
|
||||
}
|
||||
if (window.turnstile && window.turnstile.render) {
|
||||
window.turnstile.render("#captcha", {
|
||||
sitekey: siteKey,
|
||||
callback: onChange,
|
||||
});
|
||||
clearInterval(tTimer);
|
||||
}
|
||||
}, 300);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
307
web/src/common/PoliciyTable.js
Normal file
307
web/src/common/PoliciyTable.js
Normal file
@@ -0,0 +1,307 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {DeleteOutlined, EditOutlined} from "@ant-design/icons";
|
||||
import {Button, Input, Popconfirm, Table, Tooltip} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import * as AdapterBackend from "../backend/AdapterBackend";
|
||||
import i18next from "i18next";
|
||||
|
||||
class PolicyTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
policyLists: [],
|
||||
loading: false,
|
||||
editingIndex: "",
|
||||
oldPolicy: "",
|
||||
add: false,
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
if (this.props.mode === "edit") {
|
||||
this.synPolicies();
|
||||
}
|
||||
}
|
||||
|
||||
isEditing = (index) => {
|
||||
return index === this.state.editingIndex;
|
||||
};
|
||||
|
||||
edit = (record, index) => {
|
||||
this.setState({editingIndex: index, oldPolicy: Setting.deepCopy(record)});
|
||||
};
|
||||
|
||||
cancel = (table, index) => {
|
||||
Object.keys(table[index]).forEach((key) => {
|
||||
table[index][key] = this.state.oldPolicy[key];
|
||||
});
|
||||
this.updateTable(table);
|
||||
this.setState({editingIndex: "", oldPolicy: ""});
|
||||
if (this.state.add) {
|
||||
this.deleteRow(this.state.policyLists, index);
|
||||
this.setState({add: false});
|
||||
}
|
||||
};
|
||||
|
||||
updateTable(table) {
|
||||
this.setState({policyLists: table});
|
||||
}
|
||||
|
||||
updateField(table, index, key, value) {
|
||||
table[index][key] = value;
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
addRow(table) {
|
||||
const row = {Ptype: "p"};
|
||||
if (table === undefined) {
|
||||
table = [];
|
||||
}
|
||||
table = Setting.addRow(table, row, "top");
|
||||
this.updateTable(table);
|
||||
this.edit(row, 0);
|
||||
this.setState({add: true});
|
||||
}
|
||||
|
||||
deleteRow(table, i) {
|
||||
table = Setting.deleteRow(table, i);
|
||||
this.updateTable(table);
|
||||
}
|
||||
|
||||
save(table, i) {
|
||||
this.state.add ? this.addPolicy(table, i) : this.updatePolicy(table, i);
|
||||
}
|
||||
|
||||
synPolicies() {
|
||||
this.setState({loading: true});
|
||||
AdapterBackend.syncPolicies(this.props.owner, this.props.name)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({policyLists: res});
|
||||
} else {
|
||||
Setting.showMessage("error", i18next.t("adapter:Failed to sync policies: ") + res.msg);
|
||||
}
|
||||
this.setState({loading: false});
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
updatePolicy(table, i) {
|
||||
AdapterBackend.UpdatePolicy(this.props.owner, this.props.name, [this.state.oldPolicy, table[i]]).then(res => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({editingIndex: "", oldPolicy: ""});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addPolicy(table, i) {
|
||||
AdapterBackend.AddPolicy(this.props.owner, this.props.name, table[i]).then(res => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({editingIndex: "", oldPolicy: "", add: false});
|
||||
if (res.data !== "Affected") {
|
||||
Setting.showMessage("info", i18next.t("adapter:Repeated policy rules"));
|
||||
} else {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deletePolicy(table, i) {
|
||||
AdapterBackend.RemovePolicy(this.props.owner, this.props.name, table[i]).then(res => {
|
||||
if (res.status === "ok") {
|
||||
table = Setting.deleteRow(table, i);
|
||||
this.updateTable(table);
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
} else {
|
||||
Setting.showMessage("error", i18next.t("general:Failed to delete"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(table) {
|
||||
const columns = [
|
||||
{
|
||||
title: "Rule Type",
|
||||
dataIndex: "Ptype",
|
||||
width: "100px",
|
||||
// render: (text, record, index) => {
|
||||
// const editing = this.isEditing(index);
|
||||
// return (
|
||||
// editing ?
|
||||
// <Input value={text} onChange={e => {
|
||||
// this.updateField(table, index, "Ptype", e.target.value);
|
||||
// }} />
|
||||
// : text
|
||||
// );
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: "V0",
|
||||
dataIndex: "V0",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V0", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "V1",
|
||||
dataIndex: "V1",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V1", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "V2",
|
||||
dataIndex: "V2",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V2", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "V3",
|
||||
dataIndex: "V3",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V3", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "V4",
|
||||
dataIndex: "V4",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V4", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "V5",
|
||||
dataIndex: "V5",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editing = this.isEditing(index);
|
||||
return (
|
||||
editing ?
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "V5", e.target.value);
|
||||
}} />
|
||||
: text
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Option",
|
||||
key: "option",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const editable = this.isEditing(index);
|
||||
return editable ? (
|
||||
<span>
|
||||
<Button style={{marginRight: 8}} onClick={() => this.save(table, index)}>
|
||||
Save
|
||||
</Button>
|
||||
<Popconfirm title="Sure to cancel?" onConfirm={() => this.cancel(table, index)}>
|
||||
<a>Cancel</a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
) : (
|
||||
<div>
|
||||
<Tooltip placement="topLeft" title="Edit">
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Delete">
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}];
|
||||
|
||||
return (
|
||||
<Table
|
||||
pagination={{
|
||||
defaultPageSize: 10,
|
||||
}}
|
||||
columns={columns} dataSource={table} rowKey="index" size="middle" bordered
|
||||
loading={this.state.loading}
|
||||
title={() => (
|
||||
<div>
|
||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<>
|
||||
<Button type="primary" onClick={() => {this.synPolicies();}}>
|
||||
{i18next.t("adapter:Sync")}
|
||||
</Button>
|
||||
{
|
||||
this.renderTable(this.state.policyLists)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PolicyTable;
|
@@ -89,7 +89,7 @@ i18n.use(initReactI18next).init({
|
||||
keySeparator: false,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
escapeValue: true,
|
||||
},
|
||||
// debug: true,
|
||||
saveMissing: true,
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "Passwort AN",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Redirect URL": "Weiterleitungs-URL",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "Anmeldesitzung",
|
||||
"Signup items": "Artikel registrieren",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "Token läuft ab",
|
||||
"Token expire - Tooltip": "Token läuft ab - Tooltip",
|
||||
"Token format": "Token-Format",
|
||||
"Token format - Tooltip": "Token-Format - Tooltip"
|
||||
"Token format - Tooltip": "Token-Format - Tooltip",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bitgröße",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "Bitte geben Sie Ihren Benutzernamen ein!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Passwort abrufen",
|
||||
"Unknown forget type": "Unknown forget type",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "Überprüfen"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "Bearbeiten",
|
||||
"Email": "E-Mail",
|
||||
"Email - Tooltip": "email",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Favicon",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Mit {type} anmelden",
|
||||
"Signing in...": "Anmelden...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "Die Eingabe ist keine gültige E-Mail oder Telefon!",
|
||||
"To access": "Zu Zugriff",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "alarmtyp"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "Password ON",
|
||||
"Password ON - Tooltip": "Password ON - Tooltip",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Redirect URL": "Redirect URL",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Signup items - Tooltip": "Signup items - Tooltip",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Token format - Tooltip": "Token format - Tooltip",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bit size",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Unknown forget type": "Unknown forget type",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "Verify"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Email - Tooltip",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Favicon",
|
||||
"Favicon - Tooltip": "Favicon - Tooltip",
|
||||
"First name": "First name",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "alertType"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -38,6 +38,7 @@
|
||||
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copiado al portapapeles con éxito",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "Signin session",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signup items": "Signup items",
|
||||
"Signup items - Tooltip": "Signup items - Tooltip",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
@@ -45,6 +46,7 @@
|
||||
"Token expire - Tooltip": "Expiración del Token - Tooltip",
|
||||
"Token format": "Formato del Token",
|
||||
"Token format - Tooltip": "Formato del Token - Tooltip",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page",
|
||||
"Rule": "Rule",
|
||||
"None": "None",
|
||||
"Always": "Always"
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "Mot de passe activé",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Redirect URL": "URL de redirection",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "Connexion à la session",
|
||||
"Signup items": "Inscrire des éléments",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "Expiration du jeton",
|
||||
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
|
||||
"Token format": "Format du jeton",
|
||||
"Token format - Tooltip": "Format du jeton - infobulle"
|
||||
"Token format - Tooltip": "Format du jeton - infobulle",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Taille du bit",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "Veuillez entrer votre nom d'utilisateur !",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Récupérer le mot de passe",
|
||||
"Unknown forget type": "Unknown forget type",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "Vérifier"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "Editer",
|
||||
"Email": "Courriel",
|
||||
"Email - Tooltip": "email",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Favicon",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "Désolé, vous n'avez pas la permission d'accéder à cette page.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Synchronisateurs",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Se connecter avec {type}",
|
||||
"Signing in...": "Connexion en cours...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "L'entrée n'est pas valide Email ou Téléphone !",
|
||||
"To access": "Pour accéder à",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "Type d'alerte"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "パスワードON",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "HTMLファイルを選択してください",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Redirect URL": "リダイレクトURL",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "サインインセッション",
|
||||
"Signup items": "アイテムの登録",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "トークンの有効期限",
|
||||
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
|
||||
"Token format": "トークンのフォーマット",
|
||||
"Token format - Tooltip": "トークンフォーマット - ツールチップ"
|
||||
"Token format - Tooltip": "トークンフォーマット - ツールチップ",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "ビットサイズ",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "ユーザー名を入力してください!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "パスワードの取得",
|
||||
"Unknown forget type": "Unknown forget type",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "確認する"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "編集",
|
||||
"Email": "Eメールアドレス",
|
||||
"Email - Tooltip": "email",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Favicon",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "申し訳ありませんが、このページにアクセスする権限がありません。",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "{type} でサインイン",
|
||||
"Signing in...": "サインイン中...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "入力されたメールアドレスまたは電話番号が正しくありません。",
|
||||
"To access": "アクセスするには",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "alertType"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "Password ON",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Redirect URL": "Redirect URL",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Token format - Tooltip": "Token format - Tooltip",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bit size",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Unknown forget type": "Unknown forget type",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "Verify"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "email",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Favicon",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "First name",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "alertType"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "Edit Adapter",
|
||||
"Failed to sync policies: ": "Failed to sync policies: ",
|
||||
"New Adapter": "New Adapter",
|
||||
"Policies": "Policies",
|
||||
"Policies - Tooltip": "Policies - Tooltip",
|
||||
"Repeated policy rules": "Repeated policy rules",
|
||||
"Sync": "Sync"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "None",
|
||||
"Password ON": "Пароль ВКЛ",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Пожалуйста, выберите HTML-файл",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Ссылка на страницу успешно скопирована в буфер обмена, пожалуйста, вставьте ее в окно инкогнито или другой браузер",
|
||||
"Redirect URL": "URL перенаправления",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "Side panel HTML",
|
||||
"Side panel HTML - Edit": "Side panel HTML - Edit",
|
||||
"Side panel HTML - Tooltip": "Side panel HTML - Tooltip",
|
||||
"Sign Up Error": "Sign Up Error",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL страницы входа успешно скопирован в буфер обмена, пожалуйста, вставьте его в окно инкогнито или другой браузер",
|
||||
"Signin session": "Сессия входа",
|
||||
"Signup items": "Элементы регистрации",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL страницы регистрации успешно скопирован в буфер обмена, пожалуйста, вставьте его в окно инкогнито или другой браузер",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
"Token expire": "Токен истекает",
|
||||
"Token expire - Tooltip": "Истек токен - Подсказка",
|
||||
"Token format": "Формат токена",
|
||||
"Token format - Tooltip": "Формат токена - Подсказка"
|
||||
"Token format - Tooltip": "Формат токена - Подсказка",
|
||||
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Размер бита",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "Пожалуйста, введите ваше имя пользователя!",
|
||||
"Reset": "Сбросить",
|
||||
"Retrieve password": "Получить пароль",
|
||||
"Unknown forget type": "Неизвестный тип",
|
||||
"Unknown forget type: ": "Unknown forget type: ",
|
||||
"Verify": "Подтвердить"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "Редактирование",
|
||||
"Email": "Почта",
|
||||
"Email - Tooltip": "email",
|
||||
"Failed to add": "Failed to add",
|
||||
"Failed to connect to server": "Failed to connect to server",
|
||||
"Failed to delete": "Failed to delete",
|
||||
"Failed to save": "Failed to save",
|
||||
"Favicon": "Иконка",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"First name": "Имя",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "Извините, вы не имеете права доступа к этой странице.",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Successfully added": "Successfully added",
|
||||
"Successfully deleted": "Successfully deleted",
|
||||
"Successfully saved": "Successfully saved",
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Синхронизаторы",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Войти с помощью {type}",
|
||||
"Signing in...": "Вход...",
|
||||
"Successfully logged in with webauthn credentials": "Successfully logged in with webauthn credentials",
|
||||
"The input is not valid Email or Phone!": "Введен неверный адрес электронной почты или телефон!",
|
||||
"To access": "На доступ",
|
||||
"Verification Code": "Verification Code",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
|
||||
"Visible": "Visible",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "тип оповещения"
|
||||
},
|
||||
"record": {
|
||||
|
@@ -7,9 +7,11 @@
|
||||
},
|
||||
"adapter": {
|
||||
"Edit Adapter": "编辑适配器",
|
||||
"Failed to sync policies: ": "同步策略失败: ",
|
||||
"New Adapter": "添加适配器",
|
||||
"Policies": "策略",
|
||||
"Policies - Tooltip": "策略",
|
||||
"Repeated policy rules": "重复的策略",
|
||||
"Sync": "同步"
|
||||
},
|
||||
"application": {
|
||||
@@ -47,6 +49,8 @@
|
||||
"None": "关闭",
|
||||
"Password ON": "开启密码",
|
||||
"Password ON - Tooltip": "是否允许密码登录",
|
||||
"Please input your application!": "请输入你的应用",
|
||||
"Please input your organization!": "请输入你的组织",
|
||||
"Please select a HTML file": "请选择一个HTML文件",
|
||||
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "提醒页面URL已成功复制到剪贴板,请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
|
||||
"Redirect URL": "重定向 URL",
|
||||
@@ -62,15 +66,18 @@
|
||||
"Side panel HTML": "侧面板 HTML",
|
||||
"Side panel HTML - Edit": "侧面板 HTML - 编辑",
|
||||
"Side panel HTML - Tooltip": "侧面板 HTML - Tooltip",
|
||||
"Sign Up Error": "注册错误",
|
||||
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "登录页面URL已成功复制到剪贴板,请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
|
||||
"Signin session": "保持登录会话",
|
||||
"Signup items": "注册项",
|
||||
"Signup items - Tooltip": "注册用户注册时需要填写的项目",
|
||||
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "注册页面URL已成功复制到剪贴板,请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
|
||||
"The application does not allow to sign up new account": "该应用不允许注册新账户",
|
||||
"Token expire": "Access Token过期",
|
||||
"Token expire - Tooltip": "Access Token过期时间",
|
||||
"Token format": "Access Token格式",
|
||||
"Token format - Tooltip": "Access Token格式"
|
||||
"Token format - Tooltip": "Access Token格式",
|
||||
"You are unexpected to see this prompt page": "错误跳转至提醒页面"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "位大小",
|
||||
@@ -118,7 +125,7 @@
|
||||
"Please input your username!": "请输入您的用户名!",
|
||||
"Reset": "重置",
|
||||
"Retrieve password": "找回密码",
|
||||
"Unknown forget type": "未知的忘记密码类型",
|
||||
"Unknown forget type: ": "未知的忘记密码类型: ",
|
||||
"Verify": "验证"
|
||||
},
|
||||
"general": {
|
||||
@@ -157,6 +164,10 @@
|
||||
"Edit": "编辑",
|
||||
"Email": "电子邮箱",
|
||||
"Email - Tooltip": "电子邮件:",
|
||||
"Failed to add": "添加失败",
|
||||
"Failed to connect to server": "连接服务器失败",
|
||||
"Failed to delete": "删除失败",
|
||||
"Failed to save": "保存失败",
|
||||
"Favicon": "网站图标",
|
||||
"Favicon - Tooltip": "网站的Favicon图标",
|
||||
"First name": "名字",
|
||||
@@ -227,6 +238,9 @@
|
||||
"Sorry, you do not have permission to access this page.": "抱歉,您无权访问该页面",
|
||||
"State": "状态",
|
||||
"State - Tooltip": "状态",
|
||||
"Successfully added": "添加成功",
|
||||
"Successfully deleted": "删除成功",
|
||||
"Successfully saved": "保存成功",
|
||||
"Swagger": "API文档",
|
||||
"Sync": "同步",
|
||||
"Syncers": "同步器",
|
||||
@@ -292,6 +306,7 @@
|
||||
"Sign in with WebAuthn": "WebAuthn登录",
|
||||
"Sign in with {type}": "{type}登录",
|
||||
"Signing in...": "正在登录...",
|
||||
"Successfully logged in with webauthn credentials": "成功使用WebAuthn证书登录",
|
||||
"The input is not valid Email or Phone!": "您输入的电子邮箱格式或手机号有误!",
|
||||
"To access": "访问",
|
||||
"Verification Code": "验证码",
|
||||
@@ -555,6 +570,7 @@
|
||||
"UserInfo URL": "UserInfo URL",
|
||||
"UserInfo URL - Tooltip": "UserInfo URL - 工具提示",
|
||||
"Visible": "是否可见",
|
||||
"admin (share)": "admin (share)",
|
||||
"alertType": "警报类型"
|
||||
},
|
||||
"record": {
|
||||
|
Reference in New Issue
Block a user