Compare commits

...

17 Commits

Author SHA1 Message Date
e1842f6b80 feat: fix LDAP server handle filter without CN field as * (#1705)
* fix: set ldap server default filter name as *

* fix: default use built-in organization to bind

* chore: use cache reduce the ci test time
2023-04-04 20:51:28 +08:00
0781a3835d feat: improve i18n to have proper German translation in web/ (#1702) 2023-04-02 10:52:30 +08:00
98a99f0215 Fix bug in getMemoryUsage() 2023-04-02 10:50:41 +08:00
681b086de0 Fix session page highlight 2023-04-01 17:36:50 +08:00
cdcc0b39e2 feat: filter not selected provider item (#1701) 2023-04-01 10:22:18 +08:00
8eb68ba817 fix: fix AAD single-tenant mode bug 2023-03-31 19:24:03 +08:00
8d1ae4ea08 Fix organization page bug 2023-03-31 18:35:57 +08:00
9c8ea027ef feat: add the missing userId param docs for get-user API (#1698)
* Add roles to SAML response

* Fix: Add back missing get-user userId param doc.

Signed-off-by: zzjin <tczzjin@gmail.com>

* Update user.go

---------

Signed-off-by: zzjin <tczzjin@gmail.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2023-03-30 18:39:14 +08:00
aaa56d3354 Add roles to SAML response 2023-03-30 14:43:34 +08:00
b45c49d3a4 feat: fix incorrect preferred_username field mapping in OIDC (#1697) 2023-03-29 22:18:12 +08:00
5b3202cc89 feat: fix phone validation bug in signup page (#1693) 2023-03-27 22:52:49 +08:00
5280f872dc Speed up GetOAuthToken() 2023-03-27 14:05:44 +08:00
fd61b963d5 feat: [SAML + long button crash] fix Disabling "Enable password" leads to white app page when SAML provider is active (#1691)
* fix: saml long button crush

* fix: sue svg

* Update Setting.js

* Update LoginButton.js

* Update ProviderButton.js

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-03-26 23:56:43 +08:00
a8937d3046 feat: refactor agreement modal and create folders to classify components (#1686)
* refactor: refactor agreement modal and create folders to classify components

* fix: i18

* fix: i18

* fix: i18n
2023-03-26 18:44:47 +08:00
32b05047dc Update system info API swagger 2023-03-26 10:19:59 +08:00
117ee509cf feat: fix name format in application login: GetClientCredentialsToken() (#1639) 2023-03-25 23:02:08 +08:00
daf3d374b5 fix: adjust error result position (#1683) 2023-03-25 09:36:23 +08:00
72 changed files with 1262 additions and 971 deletions

View File

@ -9,18 +9,19 @@ jobs:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
cache-dependency-path: ./go.mod
- name: Tests
run: |
go test -v $(go list ./...) -tags skipCi
@ -31,14 +32,12 @@ jobs:
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
# cache
- uses: c-hive/gha-yarn-cache@v2
with:
directory: ./web
cache: 'yarn'
cache-dependency-path: ./web/yarn.lock
- run: yarn install && CI=false yarn run build
working-directory: ./web
@ -47,10 +46,11 @@ jobs:
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
cache-dependency-path: ./go.mod
- run: go version
- name: Build
run: |
@ -63,13 +63,14 @@ jobs:
needs: [ go-tests ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
cache-dependency-path: ./go.mod
# gen a dummy config file
- run: touch dummy.yml
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
@ -82,35 +83,35 @@ jobs:
needs: [ go-tests ]
services:
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
- uses: actions/setup-node@v2
with:
node-version: 16
- name: back start
cache-dependency-path: ./go.mod
- name: start backend
run: nohup go run ./main.go &
working-directory: ./
- name: front install
run: yarn install
working-directory: ./web
- name: front start
run: nohup yarn start &
working-directory: ./web
- uses: cypress-io/github-action@v4
- uses: actions/setup-node@v3
with:
working-directory: ./web
node-version: 16
cache: 'yarn'
cache-dependency-path: ./web/yarn.lock
- run: yarn install
working-directory: ./web
- uses: cypress-io/github-action@v5
with:
start: yarn start
wait-on: 'http://localhost:7001'
wait-on-timeout: 180
working-directory: ./web
- uses: actions/upload-artifact@v3
if: failure()
@ -121,7 +122,7 @@ jobs:
if: always()
with:
name: cypress-videos
path: ./web/cypress/videos
path: ./web/cypress/videos
release-and-push:
name: Release And Push
@ -130,11 +131,11 @@ jobs:
needs: [ frontend, backend, linter, e2e ]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: -1
- name: Setup Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 16
@ -166,10 +167,10 @@ jobs:
elif [ ${old_array[1]} != ${new_array[1]} ]
then
echo ::set-output name=push::'true'
else
echo ::set-output name=push::'false'
fi
- name: Set up QEMU

View File

@ -21,9 +21,8 @@ import (
// GetSystemInfo
// @Title GetSystemInfo
// @Tag System API
// @Description get user's system info
// @Param id query string true "The id ( owner/name ) of the user"
// @Success 200 {object} object.SystemInfo The Response object
// @Description get system info like CPU and memory usage
// @Success 200 {object} util.SystemInfo The Response object
// @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() {
_, ok := c.RequireAdmin()
@ -43,8 +42,8 @@ func (c *ApiController) GetSystemInfo() {
// GetVersionInfo
// @Title GetVersionInfo
// @Tag System API
// @Description get local git repo's latest release version info
// @Success 200 {string} local latest version hash of Casdoor
// @Description get version info like Casdoor release version and commit ID
// @Success 200 {object} util.VersionInfo The Response object
// @router /get-version-info [get]
func (c *ApiController) GetVersionInfo() {
versionInfo, err := util.GetVersionInfo()

View File

@ -84,6 +84,7 @@ func (c *ApiController) GetUsers() {
// @Param owner query string false "The owner of the user"
// @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user"
// @Param userId query string false "The userId of the user"
// @Success 200 {object} object.User The Response object
// @router /get-user [get]
func (c *ApiController) GetUser() {

View File

@ -108,8 +108,8 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
type CasdoorUserInfo struct {
Id string `json:"sub"`
Name string `json:"name"`
DisplayName string `json:"preferred_username"`
Name string `json:"preferred_username,omitempty"`
DisplayName string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"picture"`
Status string `json:"status"`

View File

@ -61,8 +61,8 @@ func (idp *CustomIdProvider) GetToken(code string) (*oauth2.Token, error) {
type CustomUserInfo struct {
Id string `json:"sub"`
Name string `json:"name"`
DisplayName string `json:"preferred_username"`
Name string `json:"preferred_username,omitempty"`
DisplayName string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"picture"`
Status string `json:"status"`

View File

@ -88,7 +88,7 @@ type GothIdProvider struct {
Session goth.Session
}
func NewGothIdProvider(providerType string, clientId string, clientSecret string, redirectUrl string) *GothIdProvider {
func NewGothIdProvider(providerType string, clientId string, clientSecret string, redirectUrl string, hostUrl string) *GothIdProvider {
var idp GothIdProvider
switch providerType {
case "Amazon":
@ -102,8 +102,13 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Session: &apple.Session{},
}
case "AzureAD":
domain := "common"
if hostUrl != "" {
domain = hostUrl
}
idp = GothIdProvider{
Provider: azureadv2.New(clientId, clientSecret, redirectUrl, azureadv2.ProviderOptions{Tenant: "common"}),
Provider: azureadv2.New(clientId, clientSecret, redirectUrl, azureadv2.ProviderOptions{Tenant: azureadv2.TenantType(domain)}),
Session: &azureadv2.Session{},
}
case "Auth0":

View File

@ -90,7 +90,7 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
} else if typ == "Douyin" {
return NewDouyinIdProvider(clientId, clientSecret, redirectUrl)
} else if isGothSupport(typ) {
return NewGothIdProvider(typ, clientId, clientSecret, redirectUrl)
return NewGothIdProvider(typ, clientId, clientSecret, redirectUrl, hostUrl)
} else if typ == "Bilibili" {
return NewBilibiliIdProvider(clientId, clientSecret, redirectUrl)
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
package ldap
import (
"fmt"
@ -20,76 +20,78 @@ import (
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/forestmgy/ldapserver"
ldap "github.com/forestmgy/ldapserver"
"github.com/lor00x/goldap/message"
)
func StartLdapServer() {
server := ldapserver.NewServer()
routes := ldapserver.NewRouteMux()
server := ldap.NewServer()
routes := ldap.NewRouteMux()
routes.Bind(handleBind)
routes.Search(handleSearch).Label(" SEARCH****")
server.Handle(routes)
server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
err := server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
if err != nil {
return
}
}
func handleBind(w ldapserver.ResponseWriter, m *ldapserver.Message) {
func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
r := m.GetBindRequest()
res := ldapserver.NewBindResponse(ldapserver.LDAPResultSuccess)
res := ldap.NewBindResponse(ldap.LDAPResultSuccess)
if r.AuthenticationChoice() == "simple" {
bindusername, bindorg, err := object.GetNameAndOrgFromDN(string(r.Name()))
bindUsername, bindOrg, err := getNameAndOrgFromDN(string(r.Name()))
if err != "" {
log.Printf("Bind failed ,ErrMsg=%s", err)
res.SetResultCode(ldapserver.LDAPResultInvalidDNSyntax)
res.SetResultCode(ldap.LDAPResultInvalidDNSyntax)
res.SetDiagnosticMessage("bind failed ErrMsg: " + err)
w.Write(res)
return
}
bindpassword := string(r.AuthenticationSimple())
binduser, err := object.CheckUserPassword(bindorg, bindusername, bindpassword, "en")
bindPassword := string(r.AuthenticationSimple())
bindUser, err := object.CheckUserPassword(object.CasdoorOrganization, bindUsername, bindPassword, "en")
if err != "" {
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
res.SetResultCode(ldapserver.LDAPResultInvalidCredentials)
res.SetResultCode(ldap.LDAPResultInvalidCredentials)
res.SetDiagnosticMessage("invalid credentials ErrMsg: " + err)
w.Write(res)
return
}
if bindorg == "built-in" {
if bindOrg == "built-in" || bindUser.IsGlobalAdmin {
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
} else if binduser.IsAdmin {
} else if bindUser.IsAdmin {
m.Client.IsOrgAdmin = true
}
m.Client.IsAuthenticated = true
m.Client.UserName = bindusername
m.Client.OrgName = bindorg
m.Client.UserName = bindUsername
m.Client.OrgName = bindOrg
} else {
res.SetResultCode(ldapserver.LDAPResultAuthMethodNotSupported)
res.SetResultCode(ldap.LDAPResultAuthMethodNotSupported)
res.SetDiagnosticMessage("Authentication method not supported,Please use Simple Authentication")
}
w.Write(res)
}
func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
res := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultSuccess)
func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
res := ldap.NewSearchResultDoneResponse(ldap.LDAPResultSuccess)
if !m.Client.IsAuthenticated {
res.SetResultCode(ldapserver.LDAPResultUnwillingToPerform)
res.SetResultCode(ldap.LDAPResultUnwillingToPerform)
w.Write(res)
return
}
r := m.GetSearchRequest()
if r.FilterString() == "(objectClass=*)" {
w.Write(res)
return
}
name, org, errCode := object.GetUserNameAndOrgFromBaseDnAndFilter(string(r.BaseObject()), r.FilterString())
if errCode != ldapserver.LDAPResultSuccess {
res.SetResultCode(errCode)
w.Write(res)
return
}
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
select {
case <-m.Done:
@ -97,16 +99,17 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
return
default:
}
users, errCode := object.GetFilteredUsers(m, name, org)
if errCode != ldapserver.LDAPResultSuccess {
res.SetResultCode(errCode)
users, code := GetFilteredUsers(m)
if code != ldap.LDAPResultSuccess {
res.SetResultCode(code)
w.Write(res)
return
}
for i := 0; i < len(users); i++ {
user := users[i]
for _, user := range users {
dn := fmt.Sprintf("cn=%s,%s", user.Name, string(r.BaseObject()))
e := ldapserver.NewSearchResultEntry(dn)
e := ldap.NewSearchResultEntry(dn)
e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Name))
e.AddAttribute("email", message.AttributeValue(user.Email))
@ -117,22 +120,3 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
}
w.Write(res)
}
// get user password with hash type prefix
// TODO not handle salt yet
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
func getUserPasswordWithType(user *object.User) string {
org := object.GetOrganizationByUser(user)
if org.PasswordType == "" || org.PasswordType == "plain" {
return user.Password
}
prefix := org.PasswordType
if prefix == "salt" {
prefix = "sha256"
} else if prefix == "md5-salt" {
prefix = "md5"
} else if prefix == "pbkdf2-salt" {
prefix = "pbkdf2"
}
return fmt.Sprintf("{%s}%s", prefix, user.Password)
}

116
ldap/util.go Normal file
View File

@ -0,0 +1,116 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ldap
import (
"fmt"
"log"
"strings"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
ldap "github.com/forestmgy/ldapserver"
)
func getNameAndOrgFromDN(DN string) (string, string, string) {
DNFields := strings.Split(DN, ",")
params := make(map[string]string, len(DNFields))
for _, field := range DNFields {
if strings.Contains(field, "=") {
k := strings.Split(field, "=")
params[k[0]] = k[1]
}
}
if params["cn"] == "" {
return "", "", "please use Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
}
if params["ou"] == "" {
return params["cn"], object.CasdoorOrganization, ""
}
return params["cn"], params["ou"], ""
}
func getNameAndOrgFromFilter(baseDN, filter string) (string, string, int) {
if !strings.Contains(baseDN, "ou=") {
return "", "", ldap.LDAPResultInvalidDNSyntax
}
name, org, _ := getNameAndOrgFromDN(fmt.Sprintf("cn=%s,", getUsername(filter)) + baseDN)
return name, org, ldap.LDAPResultSuccess
}
func getUsername(filter string) string {
nameIndex := strings.Index(filter, "cn=")
if nameIndex == -1 {
return "*"
}
var name string
for i := nameIndex + 3; filter[i] != ')'; i++ {
name = name + string(filter[i])
}
return name
}
func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) {
r := m.GetSearchRequest()
name, org, code := getNameAndOrgFromFilter(string(r.BaseObject()), r.FilterString())
if code != ldap.LDAPResultSuccess {
return nil, code
}
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
if m.Client.IsGlobalAdmin && org == "*" {
filteredUsers = object.GetGlobalUsers()
return filteredUsers, ldap.LDAPResultSuccess
}
if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
filteredUsers = object.GetUsers(org)
return filteredUsers, ldap.LDAPResultSuccess
} else {
return nil, ldap.LDAPResultInsufficientAccessRights
}
} else {
hasPermission, err := object.CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true, "en")
if !hasPermission {
log.Printf("ErrMsg = %v", err.Error())
return nil, ldap.LDAPResultInsufficientAccessRights
}
user := object.GetUser(util.GetId(org, name))
filteredUsers = append(filteredUsers, user)
return filteredUsers, ldap.LDAPResultSuccess
}
}
// get user password with hash type prefix
// TODO not handle salt yet
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
func getUserPasswordWithType(user *object.User) string {
org := object.GetOrganizationByUser(user)
if org.PasswordType == "" || org.PasswordType == "plain" {
return user.Password
}
prefix := org.PasswordType
if prefix == "salt" {
prefix = "sha256"
} else if prefix == "md5-salt" {
prefix = "md5"
} else if prefix == "pbkdf2-salt" {
prefix = "pbkdf2"
}
return fmt.Sprintf("{%s}%s", prefix, user.Password)
}

View File

@ -23,7 +23,7 @@ import (
_ "github.com/beego/beego/session/redis"
"github.com/casdoor/casdoor/authz"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/controllers"
"github.com/casdoor/casdoor/ldap"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/routers"
@ -81,7 +81,7 @@ func main() {
// logs.SetLevel(logs.LevelInformational)
logs.SetLogFuncCall(false)
go controllers.StartLdapServer()
go ldap.StartLdapServer()
beego.Run(fmt.Sprintf(":%v", port))
}

View File

@ -115,7 +115,7 @@ func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser {
}
func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
SearchFilter := "(objectclass=*)"
SearchFilter := "(objectClass=*)"
SearchAttributes := []string{"vendorname", "vendorversion", "isGlobalCatalogReady", "forestFunctionality"}
searchReq := goldap.NewSearchRequest("",
@ -126,7 +126,7 @@ func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
return false, err
}
if len(searchResult.Entries) == 0 {
return false, errors.New("no result")
return false, nil
}
isMicrosoft := false
var ldapServerType ldapServerType

View File

@ -1,74 +0,0 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"log"
"strings"
"github.com/forestmgy/ldapserver"
)
func GetNameAndOrgFromDN(DN string) (string, string, string) {
DNValue := strings.Split(DN, ",")
if len(DNValue) == 1 || strings.ToLower(DNValue[0])[0] != 'c' || strings.ToLower(DNValue[1])[0] != 'o' {
return "", "", "please use correct Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
}
return DNValue[0][3:], DNValue[1][3:], ""
}
func GetUserNameAndOrgFromBaseDnAndFilter(baseDN, filter string) (string, string, int) {
if !strings.Contains(baseDN, "ou=") || !strings.Contains(filter, "cn=") {
return "", "", ldapserver.LDAPResultInvalidDNSyntax
}
name := getUserNameFromFilter(filter)
_, org, _ := GetNameAndOrgFromDN(fmt.Sprintf("cn=%s,", name) + baseDN)
errCode := ldapserver.LDAPResultSuccess
return name, org, errCode
}
func getUserNameFromFilter(filter string) string {
nameIndex := strings.Index(filter, "cn=")
var name string
for i := nameIndex + 3; filter[i] != ')'; i++ {
name = name + string(filter[i])
}
return name
}
func GetFilteredUsers(m *ldapserver.Message, name, org string) ([]*User, int) {
var filteredUsers []*User
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
if m.Client.OrgName == "built-in" && org == "*" {
filteredUsers = GetGlobalUsers()
return filteredUsers, ldapserver.LDAPResultSuccess
} else if m.Client.OrgName == "built-in" || org == m.Client.OrgName {
filteredUsers = GetUsers(org)
return filteredUsers, ldapserver.LDAPResultSuccess
} else {
return nil, ldapserver.LDAPResultInsufficientAccessRights
}
} else {
hasPermission, err := CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true, "en")
if !hasPermission {
log.Printf("ErrMsg = %v", err.Error())
return nil, ldapserver.LDAPResultInsufficientAccessRights
}
user := getUser(org, name)
filteredUsers = append(filteredUsers, user)
return filteredUsers, ldapserver.LDAPResultSuccess
}
}

View File

@ -86,19 +86,30 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
authnStatement.CreateElement("saml:AuthnContext").CreateElement("saml:AuthnContextClassRef").SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")
attributes := assertion.CreateElement("saml:AttributeStatement")
email := attributes.CreateElement("saml:Attribute")
email.CreateAttr("Name", "Email")
email.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
email.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(user.Email)
name := attributes.CreateElement("saml:Attribute")
name.CreateAttr("Name", "Name")
name.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
name.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(user.Name)
displayName := attributes.CreateElement("saml:Attribute")
displayName.CreateAttr("Name", "DisplayName")
displayName.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
displayName.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(user.DisplayName)
roles := attributes.CreateElement("saml:Attribute")
roles.CreateAttr("Name", "Roles")
roles.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
ExtendUserWithRolesAndPermissions(user)
for _, role := range user.Roles {
roles.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(role.Name)
}
return samlResponse, nil
}

View File

@ -51,7 +51,7 @@ type Token struct {
Organization string `xorm:"varchar(100)" json:"organization"`
User string `xorm:"varchar(100)" json:"user"`
Code string `xorm:"varchar(100)" json:"code"`
Code string `xorm:"varchar(100) index" json:"code"`
AccessToken string `xorm:"mediumtext" json:"accessToken"`
RefreshToken string `xorm:"mediumtext" json:"refreshToken"`
ExpiresIn int `json:"expiresIn"`
@ -362,7 +362,8 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
}
token.CodeIsUsed = true
updateUsedByCode(token)
go updateUsedByCode(token)
tokenWrapper := &TokenWrapper{
AccessToken: token.AccessToken,
IdToken: token.AccessToken,
@ -613,7 +614,8 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
nullUser := &User{
Owner: application.Owner,
Id: application.GetId(),
Name: fmt.Sprintf("app/%s", application.Name),
Name: application.Name,
Type: "application",
}
accessToken, _, tokenName, err := generateJwtToken(application, nullUser, "", scope, host)

View File

@ -2058,22 +2058,13 @@
"tags": [
"System API"
],
"description": "get user's system info",
"description": "get system info like CPU and memory usage",
"operationId": "ApiController.GetSystemInfo",
"parameters": [
{
"in": "query",
"name": "id",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/object.SystemInfo"
"$ref": "#/definitions/util.SystemInfo"
}
}
}
@ -2180,6 +2171,12 @@
"name": "phone",
"description": "The phone of the user",
"type": "string"
},
{
"in": "query",
"name": "userId",
"description": "The userId of the user",
"type": "string"
}
],
"responses": {
@ -2323,11 +2320,14 @@
"tags": [
"System API"
],
"description": "get local git repo's latest release version info",
"description": "get version info like Casdoor release version and commit ID",
"operationId": "ApiController.GetVersionInfo",
"responses": {
"200": {
"description": "{string} local latest version hash of Casdoor"
"description": "The Response object",
"schema": {
"$ref": "#/definitions/util.VersionInfo"
}
}
}
}
@ -3494,6 +3494,23 @@
"operationId": "ApiController.UploadResource"
}
},
"/api/user": {
"get": {
"tags": [
"Account API"
],
"description": "return Laravel compatible user information according to OAuth 2.0",
"operationId": "ApiController.UserInfo2",
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/LaravelResponse"
}
}
}
}
},
"/api/userinfo": {
"get": {
"tags": [
@ -3627,14 +3644,18 @@
}
},
"definitions": {
"2268.0xc000528cf0.false": {
"2306.0xc0003a4480.false": {
"title": "false",
"type": "object"
},
"2302.0xc000528d20.false": {
"2340.0xc0003a44b0.false": {
"title": "false",
"type": "object"
},
"LaravelResponse": {
"title": "LaravelResponse",
"type": "object"
},
"Response": {
"title": "Response",
"type": "object"
@ -3682,6 +3703,9 @@
"captchaType": {
"type": "string"
},
"clientId": {
"type": "string"
},
"clientSecret": {
"type": "string"
},
@ -3758,10 +3782,10 @@
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/2268.0xc000528cf0.false"
"$ref": "#/definitions/2306.0xc0003a4480.false"
},
"data2": {
"$ref": "#/definitions/2302.0xc000528d20.false"
"$ref": "#/definitions/2340.0xc0003a44b0.false"
},
"msg": {
"type": "string"
@ -4830,10 +4854,6 @@
}
}
},
"object.SystemInfo": {
"title": "SystemInfo",
"type": "object"
},
"object.TableColumn": {
"title": "TableColumn",
"type": "object",
@ -5475,6 +5495,43 @@
"title": "CredentialCreationResponse",
"type": "object"
},
"util.SystemInfo": {
"title": "SystemInfo",
"type": "object",
"properties": {
"cpuUsage": {
"type": "array",
"items": {
"type": "number",
"format": "double"
}
},
"memoryTotal": {
"type": "integer",
"format": "int64"
},
"memoryUsed": {
"type": "integer",
"format": "int64"
}
}
},
"util.VersionInfo": {
"title": "VersionInfo",
"type": "object",
"properties": {
"commitId": {
"type": "string"
},
"commitOffset": {
"type": "integer",
"format": "int64"
},
"version": {
"type": "string"
}
}
},
"webauthn.Credential": {
"title": "Credential",
"type": "object"

View File

@ -1340,19 +1340,13 @@ paths:
get:
tags:
- System API
description: get user's system info
description: get system info like CPU and memory usage
operationId: ApiController.GetSystemInfo
parameters:
- in: query
name: id
description: The id ( owner/name ) of the user
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.SystemInfo'
$ref: '#/definitions/util.SystemInfo'
/api/get-token:
get:
tags:
@ -1423,6 +1417,10 @@ paths:
name: phone
description: The phone of the user
type: string
- in: query
name: userId
description: The userId of the user
type: string
responses:
"200":
description: The Response object
@ -1515,11 +1513,13 @@ paths:
get:
tags:
- System API
description: get local git repo's latest release version info
description: get version info like Casdoor release version and commit ID
operationId: ApiController.GetVersionInfo
responses:
"200":
description: '{string} local latest version hash of Casdoor'
description: The Response object
schema:
$ref: '#/definitions/util.VersionInfo'
/api/get-webhook:
get:
tags:
@ -2288,6 +2288,17 @@ paths:
tags:
- Resource API
operationId: ApiController.UploadResource
/api/user:
get:
tags:
- Account API
description: return Laravel compatible user information according to OAuth 2.0
operationId: ApiController.UserInfo2
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/LaravelResponse'
/api/userinfo:
get:
tags:
@ -2374,12 +2385,15 @@ paths:
schema:
$ref: '#/definitions/Response'
definitions:
2268.0xc000528cf0.false:
2306.0xc0003a4480.false:
title: "false"
type: object
2302.0xc000528d20.false:
2340.0xc0003a44b0.false:
title: "false"
type: object
LaravelResponse:
title: LaravelResponse
type: object
Response:
title: Response
type: object
@ -2413,6 +2427,8 @@ definitions:
type: string
captchaType:
type: string
clientId:
type: string
clientSecret:
type: string
code:
@ -2464,9 +2480,9 @@ definitions:
type: object
properties:
data:
$ref: '#/definitions/2268.0xc000528cf0.false'
$ref: '#/definitions/2306.0xc0003a4480.false'
data2:
$ref: '#/definitions/2302.0xc000528d20.false'
$ref: '#/definitions/2340.0xc0003a44b0.false'
msg:
type: string
name:
@ -3183,9 +3199,6 @@ definitions:
type: string
user:
type: string
object.SystemInfo:
title: SystemInfo
type: object
object.TableColumn:
title: TableColumn
type: object
@ -3617,6 +3630,32 @@ definitions:
protocol.CredentialCreationResponse:
title: CredentialCreationResponse
type: object
util.SystemInfo:
title: SystemInfo
type: object
properties:
cpuUsage:
type: array
items:
type: number
format: double
memoryTotal:
type: integer
format: int64
memoryUsed:
type: integer
format: int64
util.VersionInfo:
title: VersionInfo
type: object
properties:
commitId:
type: string
commitOffset:
type: integer
format: int64
version:
type: string
webauthn.Credential:
title: Credential
type: object

View File

@ -59,7 +59,7 @@ func getMemoryUsage() (uint64, uint64, error) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
return m.TotalAlloc, virtualMem.Total, nil
return m.Alloc, virtualMem.Total, nil
}
func GetSystemInfo() (*SystemInfo, error) {

View File

@ -21,7 +21,7 @@ import i18next from "i18next";
import "codemirror/lib/codemirror.css";
import * as ModelBackend from "./backend/ModelBackend";
import PolicyTable from "./common/PoliciyTable";
import PolicyTable from "./table/PoliciyTable";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/javascript/javascript");

View File

@ -52,7 +52,7 @@ import PaymentEditPage from "./PaymentEditPage";
import PaymentResultPage from "./PaymentResultPage";
import AccountPage from "./account/AccountPage";
import HomePage from "./basic/HomePage";
import CustomGithubCorner from "./CustomGithubCorner";
import CustomGithubCorner from "./common/CustomGithubCorner";
import * as Conf from "./Conf";
import * as Auth from "./auth/Auth";
@ -60,7 +60,7 @@ import EntryPage from "./EntryPage";
import ResultPage from "./auth/ResultPage";
import * as AuthBackend from "./auth/AuthBackend";
import AuthCallback from "./auth/AuthCallback";
import SelectLanguageBox from "./SelectLanguageBox";
import LanguageSelect from "./common/select/LanguageSelect";
import i18next from "i18next";
import OdicDiscoveryPage from "./auth/OidcDiscoveryPage";
import SamlCallback from "./auth/SamlCallback";
@ -70,7 +70,7 @@ import SystemInfo from "./SystemInfo";
import AdapterListPage from "./AdapterListPage";
import AdapterEditPage from "./AdapterEditPage";
import {withTranslation} from "react-i18next";
import SelectThemeBox from "./SelectThemeBox";
import ThemeSelect from "./common/select/ThemeSelect";
import SessionListPage from "./SessionListPage";
const {Header, Footer, Content} = Layout;
@ -135,10 +135,12 @@ class App extends Component {
this.setState({selectedMenuKey: "/applications"});
} else if (uri.includes("/resources")) {
this.setState({selectedMenuKey: "/resources"});
} else if (uri.includes("/tokens")) {
this.setState({selectedMenuKey: "/tokens"});
} else if (uri.includes("/records")) {
this.setState({selectedMenuKey: "/records"});
} else if (uri.includes("/tokens")) {
this.setState({selectedMenuKey: "/tokens"});
} else if (uri.includes("/sessions")) {
this.setState({selectedMenuKey: "/sessions"});
} else if (uri.includes("/webhooks")) {
this.setState({selectedMenuKey: "/webhooks"});
} else if (uri.includes("/syncers")) {
@ -352,7 +354,7 @@ class App extends Component {
return (
<React.Fragment>
{this.renderRightDropdown()}
<SelectThemeBox
<ThemeSelect
themeAlgorithm={this.state.themeAlgorithm}
onChange={(nextThemeAlgorithm) => {
this.setState({
@ -360,7 +362,7 @@ class App extends Component {
logo: this.getLogo(nextThemeAlgorithm),
});
}} />
<SelectLanguageBox languages={this.state.account.organization.languages} />
<LanguageSelect languages={this.state.account.organization.languages} />
</React.Fragment>
);
}

View File

@ -25,9 +25,9 @@ import * as ResourceBackend from "./backend/ResourceBackend";
import SignupPage from "./auth/SignupPage";
import LoginPage from "./auth/LoginPage";
import i18next from "i18next";
import UrlTable from "./UrlTable";
import ProviderTable from "./ProviderTable";
import SignupTable from "./SignupTable";
import UrlTable from "./table/UrlTable";
import ProviderTable from "./table/ProviderTable";
import SignupTable from "./table/SignupTable";
import PromptPage from "./auth/PromptPage";
import copy from "copy-to-clipboard";
@ -867,6 +867,8 @@ class ApplicationEditPage extends React.Component {
submitApplicationEdit(willExist) {
const application = Setting.deepCopy(this.state.application);
application.providers = application.providers?.filter(provider => this.state.providers.map(provider => provider.name).includes(provider.name));
ApplicationBackend.updateApplication("admin", this.state.applicationName, application)
.then((res) => {
if (res.status === "ok") {

View File

@ -21,8 +21,8 @@ import * as Setting from "./Setting";
import * as Conf from "./Conf";
import i18next from "i18next";
import {LinkOutlined} from "@ant-design/icons";
import LdapTable from "./LdapTable";
import AccountTable from "./AccountTable";
import LdapTable from "./table/LdapTable";
import AccountTable from "./table/AccountTable";
import ThemeEditor from "./common/theme/ThemeEditor";
const {Option} = Select;

View File

@ -19,12 +19,12 @@ import * as ProviderBackend from "./backend/ProviderBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import {authConfig} from "./auth/Auth";
import * as ProviderEditTestEmail from "./TestEmailWidget";
import * as ProviderEditTestSms from "./TestSmsWidget";
import * as ProviderEditTestEmail from "./common/TestEmailWidget";
import * as ProviderEditTestSms from "./common/TestSmsWidget";
import copy from "copy-to-clipboard";
import {CaptchaPreview} from "./common/CaptchaPreview";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import {CountryCodeSelect} from "./common/CountryCodeSelect";
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
const {Option} = Select;
const {TextArea} = Input;
@ -110,7 +110,7 @@ class ProviderEditPage extends React.Component {
getClientSecretLabel(provider) {
switch (provider.category) {
case "Email":
return Setting.getLabel(i18next.t("login:Password"), i18next.t("login:Password - Tooltip"));
return Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"));
case "SMS":
if (provider.type === "Volc Engine SMS") {
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:Secret access key - Tooltip"));
@ -130,6 +130,24 @@ class ProviderEditPage extends React.Component {
}
}
getProviderSubTypeOptions(type) {
if (type === "WeCom" || type === "Infoflow") {
return (
[
{id: "Internal", name: i18next.t("provider:Internal")},
{id: "Third-party", name: i18next.t("provider:Third-party")},
]
);
} else if (type === "Aliyun Captcha") {
return [
{id: "nc", name: i18next.t("provider:Sliding Validation")},
{id: "ic", name: i18next.t("provider:Intelligent Validation")},
];
} else {
return [];
}
}
getAppIdRow(provider) {
let text = "";
let tooltip = "";
@ -315,7 +333,7 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("subType", value);
}}>
{
Setting.getProviderSubTypeOptions(this.state.provider.type).map((providerSubType, index) => <Option key={index} value={providerSubType.id}>{providerSubType.name}</Option>)
this.getProviderSubTypeOptions(this.state.provider.type).map((providerSubType, index) => <Option key={index} value={providerSubType.id}>{providerSubType.name}</Option>)
}
</Select>
</Col>
@ -331,7 +349,10 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("method", value);
}}>
{
[{name: "Normal"}, {name: "Silent"}].map((method, index) => <Option key={index} value={method.name}>{method.name}</Option>)
[
{id: "Normal", name: i18next.t("provider:Normal")},
{id: "Silent", name: i18next.t("provider:Silent")},
].map((method, index) => <Option key={index} value={method.name}>{method.name}</Option>)
}
</Select>
</Col>

View File

@ -14,7 +14,7 @@
import React from "react";
import {Link} from "react-router-dom";
import {Checkbox, Form, Modal, Select, Tag, Tooltip, message, theme} from "antd";
import {Select, Tag, Tooltip, message, theme} from "antd";
import {QuestionCircleTwoTone} from "@ant-design/icons";
import {isMobile as isMobileDevice} from "react-device-detect";
import "./i18n";
@ -552,10 +552,6 @@ export function addRow(array, row, position = "end") {
return position === "end" ? [...array, row] : [row, ...array];
}
export function prependRow(array, row) {
return [row, ...array];
}
export function deleteRow(array, i) {
// return array = array.slice(0, i).concat(array.slice(i + 1));
return [...array.slice(0, i), ...array.slice(i + 1)];
@ -585,76 +581,6 @@ export function isMobile() {
return isMobileDevice;
}
export function getTermsOfUseContent(url, setTermsOfUseContent) {
fetch(url, {
method: "GET",
}).then(r => {
r.text().then(setTermsOfUseContent);
});
}
export function isAgreementRequired(application) {
if (application) {
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
if (!agreementItem || agreementItem.rule === "None" || !agreementItem.rule) {
return false;
}
if (agreementItem.required) {
return true;
}
}
return false;
}
export function isDefaultTrue(application) {
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
return isAgreementRequired(application) && agreementItem.rule === "Signin (Default True)";
}
export function renderAgreement(required, onClick, noStyle, layout, initialValue) {
return (
<Form.Item
name="agreement"
key="agreement"
valuePropName="checked"
rules={[
{
required: required,
message: i18next.t("signup:Please accept the agreement!"),
},
]}
{...layout}
noStyle={noStyle}
initialValue={initialValue}
>
<Checkbox style={{float: "left"}}>
{i18next.t("signup:Accept")}&nbsp;
<a onClick={onClick}>
{i18next.t("signup:Terms of Use")}
</a>
</Checkbox>
</Form.Item>
);
}
export function renderModal(isOpen, onOk, onCancel, doc) {
return (
<Modal
title={i18next.t("signup:Terms of Use")}
open={isOpen}
width={"55vw"}
closable={false}
okText={i18next.t("signup:Accept")}
cancelText={i18next.t("signup:Decline")}
onOk={onOk}
onCancel={onCancel}
>
<iframe title={"terms"} style={{border: 0, width: "100%", height: "60vh"}} srcDoc={doc} />
</Modal>
);
}
export function getFormattedDate(date) {
if (date === undefined) {
return null;
@ -731,14 +657,6 @@ export function getAvatarColor(s) {
return colorList[hash % 4];
}
export function getLogo(theme) {
if (theme === "Dark") {
return `${StaticBaseUrl}/img/casdoor-logo_1185x256_dark.png`;
} else {
return `${StaticBaseUrl}/img/casdoor-logo_1185x256.png`;
}
}
export function getLanguageText(text) {
if (!text.includes("|")) {
return text;
@ -763,11 +681,6 @@ export function setLanguage(language) {
i18next.changeLanguage(language);
}
export function setTheme(themeKey) {
localStorage.setItem("theme", themeKey);
dispatchEvent(new Event("changeTheme"));
}
export function getAcceptLanguage() {
if (i18next.language === null || i18next.language === "") {
return "en;q=0.9,en;q=0.8";
@ -948,24 +861,6 @@ export function getProviderTypeOptions(category) {
}
}
export function getProviderSubTypeOptions(type) {
if (type === "WeCom" || type === "Infoflow") {
return (
[
{id: "Internal", name: "Internal"},
{id: "Third-party", name: "Third-party"},
]
);
} else if (type === "Aliyun Captcha") {
return [
{id: "nc", name: "Sliding Validation"},
{id: "ic", name: "Intelligent Validation"},
];
} else {
return [];
}
}
export function renderLogo(application) {
if (application === null) {
return null;
@ -1239,94 +1134,3 @@ export function inIframe() {
return true;
}
}
export function getSyncerTableColumns(syncer) {
switch (syncer.type) {
case "Keycloak":
return [
{
"name": "ID",
"type": "string",
"casdoorName": "Id",
"isHashed": true,
"values": [
],
},
{
"name": "USERNAME",
"type": "string",
"casdoorName": "Name",
"isHashed": true,
"values": [
],
},
{
"name": "LAST_NAME+FIRST_NAME",
"type": "string",
"casdoorName": "DisplayName",
"isHashed": true,
"values": [
],
},
{
"name": "EMAIL",
"type": "string",
"casdoorName": "Email",
"isHashed": true,
"values": [
],
},
{
"name": "EMAIL_VERIFIED",
"type": "boolean",
"casdoorName": "EmailVerified",
"isHashed": true,
"values": [
],
},
{
"name": "FIRST_NAME",
"type": "string",
"casdoorName": "FirstName",
"isHashed": true,
"values": [
],
},
{
"name": "LAST_NAME",
"type": "string",
"casdoorName": "LastName",
"isHashed": true,
"values": [
],
},
{
"name": "CREATED_TIMESTAMP",
"type": "string",
"casdoorName": "CreatedTime",
"isHashed": true,
"values": [
],
},
{
"name": "ENABLED",
"type": "boolean",
"casdoorName": "IsForbidden",
"isHashed": true,
"values": [
],
},
];
default:
return [];
}
}

View File

@ -19,7 +19,7 @@ import * as SyncerBackend from "./backend/SyncerBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import SyncerTableColumnTable from "./SyncerTableColumnTable";
import SyncerTableColumnTable from "./table/SyncerTableColumnTable";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
@ -80,6 +80,97 @@ class SyncerEditPage extends React.Component {
});
}
getSyncerTableColumns(syncer) {
switch (syncer.type) {
case "Keycloak":
return [
{
"name": "ID",
"type": "string",
"casdoorName": "Id",
"isHashed": true,
"values": [
],
},
{
"name": "USERNAME",
"type": "string",
"casdoorName": "Name",
"isHashed": true,
"values": [
],
},
{
"name": "LAST_NAME+FIRST_NAME",
"type": "string",
"casdoorName": "DisplayName",
"isHashed": true,
"values": [
],
},
{
"name": "EMAIL",
"type": "string",
"casdoorName": "Email",
"isHashed": true,
"values": [
],
},
{
"name": "EMAIL_VERIFIED",
"type": "boolean",
"casdoorName": "EmailVerified",
"isHashed": true,
"values": [
],
},
{
"name": "FIRST_NAME",
"type": "string",
"casdoorName": "FirstName",
"isHashed": true,
"values": [
],
},
{
"name": "LAST_NAME",
"type": "string",
"casdoorName": "LastName",
"isHashed": true,
"values": [
],
},
{
"name": "CREATED_TIMESTAMP",
"type": "string",
"casdoorName": "CreatedTime",
"isHashed": true,
"values": [
],
},
{
"name": "ENABLED",
"type": "boolean",
"casdoorName": "IsForbidden",
"isHashed": true,
"values": [
],
},
];
default:
return [];
}
}
renderSyncer() {
return (
<Card size="small" title={
@ -120,7 +211,7 @@ class SyncerEditPage extends React.Component {
<Select virtual={false} style={{width: "100%"}} value={this.state.syncer.type} onChange={(value => {
this.updateSyncerField("type", value);
const syncer = this.state.syncer;
syncer["tableColumns"] = Setting.getSyncerTableColumns(this.state.syncer);
syncer["tableColumns"] = this.getSyncerTableColumns(this.state.syncer);
syncer.table = (value === "Keycloak") ? "user_entity" : this.state.syncer.table;
this.setState({
syncer: syncer,

View File

@ -45,7 +45,7 @@ class SystemInfo extends React.Component {
}).catch(error => {
Setting.showMessage("error", `System info failed to get: ${error}`);
});
}, 1000 * 3);
}, 1000 * 2);
this.setState({intervalId: id});
}).catch(error => {
Setting.showMessage("error", `System info failed to get: ${error}`);

View File

@ -18,18 +18,18 @@ import * as UserBackend from "./backend/UserBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import CropperDiv from "./CropperDiv.js";
import CropperDivModal from "./common/modal/CropperDivModal.js";
import * as ApplicationBackend from "./backend/ApplicationBackend";
import PasswordModal from "./PasswordModal";
import ResetModal from "./ResetModal";
import AffiliationSelect from "./common/AffiliationSelect";
import PasswordModal from "./common/modal/PasswordModal";
import ResetModal from "./common/modal/ResetModal";
import AffiliationSelect from "./common/select/AffiliationSelect";
import OAuthWidget from "./common/OAuthWidget";
import SamlWidget from "./common/SamlWidget";
import SelectRegionBox from "./SelectRegionBox";
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
import ManagedAccountTable from "./ManagedAccountTable";
import PropertyTable from "./propertyTable";
import {CountryCodeSelect} from "./common/CountryCodeSelect";
import RegionSelect from "./common/select/RegionSelect";
import WebAuthnCredentialTable from "./table/WebauthnCredentialTable";
import ManagedAccountTable from "./table/ManagedAccountTable";
import PropertyTable from "./table/propertyTable";
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
const {Option} = Select;
@ -253,7 +253,7 @@ class UserEditPage extends React.Component {
</Col>
</Row>
<Row style={{marginTop: "20px"}}>
<CropperDiv buttonText={`${i18next.t("user:Upload a photo")}...`} title={i18next.t("user:Upload a photo")} user={this.state.user} organization={this.state.organizations.find(organization => organization.name === this.state.organizationName)} />
<CropperDivModal buttonText={`${i18next.t("user:Upload a photo")}...`} title={i18next.t("user:Upload a photo")} user={this.state.user} organization={this.state.organizations.find(organization => organization.name === this.state.organizationName)} />
</Row>
</Col>
</Row>
@ -341,7 +341,7 @@ class UserEditPage extends React.Component {
{Setting.getLabel(i18next.t("user:Country/Region"), i18next.t("user:Country/Region - Tooltip"))} :
</Col>
<Col span={22} >
<SelectRegionBox defaultValue={this.state.user.region} onChange={(value) => {
<RegionSelect defaultValue={this.state.user.region} onChange={(value) => {
this.updateUserField("region", value);
}} />
</Col>
@ -614,7 +614,7 @@ class UserEditPage extends React.Component {
);
}
submitUserEdit(willExist) {
submitUserEdit(needExit) {
const user = Setting.deepCopy(this.state.user);
UserBackend.updateUser(this.state.organizationName, this.state.userName, user)
.then((res) => {
@ -626,13 +626,18 @@ class UserEditPage extends React.Component {
});
if (this.props.history !== undefined) {
if (willExist) {
this.props.history.push("/users");
if (needExit) {
const userListUrl = sessionStorage.getItem("userListUrl");
if (userListUrl !== null) {
this.props.history.push(userListUrl);
} else {
this.props.history.push("/users");
}
} else {
this.props.history.push(`/users/${this.state.user.owner}/${this.state.user.name}`);
}
} else {
if (willExist) {
if (needExit) {
if (this.state.returnUrl) {
window.location.href = this.state.returnUrl;
}

View File

@ -70,6 +70,7 @@ class UserListPage extends BaseListPage {
UserBackend.addUser(newUser)
.then((res) => {
if (res.status === "ok") {
sessionStorage.setItem("userListUrl", window.location.pathname);
this.props.history.push({pathname: `/users/${newUser.owner}/${newUser.name}`, mode: "add"});
Setting.showMessage("success", i18next.t("general:Successfully added"));
} else {
@ -341,7 +342,10 @@ class UserListPage extends BaseListPage {
const disabled = (record.owner === this.props.account.owner && record.name === this.props.account.name);
return (
<div>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/users/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => {
sessionStorage.setItem("userListUrl", window.location.pathname);
this.props.history.push(`/users/${record.owner}/${record.name}`);
}}>{i18next.t("general:Edit")}</Button>
<PopconfirmModal
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
onConfirm={() => this.deleteUser(index)}
@ -402,6 +406,8 @@ class UserListPage extends BaseListPage {
const users = res.data;
if (users.length > 0) {
this.getOrganization(users[0].owner);
} else {
this.getOrganization(this.state.organizationName);
}
} else {
if (Setting.isResponseDenied(res)) {
@ -430,6 +436,8 @@ class UserListPage extends BaseListPage {
const users = res.data;
if (users.length > 0) {
this.getOrganization(users[0].owner);
} else {
this.getOrganization(this.state.organizationName);
}
} else {
if (Setting.isResponseDenied(res)) {

View File

@ -19,7 +19,7 @@ import * as WebhookBackend from "./backend/WebhookBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import WebhookHeaderTable from "./WebhookHeaderTable";
import WebhookHeaderTable from "./table/WebhookHeaderTable";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";

View File

@ -22,7 +22,7 @@ import i18next from "i18next";
import {SendCodeInput} from "../common/SendCodeInput";
import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../CustomGithubCorner";
import CustomGithubCorner from "../common/CustomGithubCorner";
import {withRouter} from "react-router-dom";
const {Option} = Select;

View File

@ -14,11 +14,10 @@
import i18next from "i18next";
import {createButton} from "react-social-login-buttons";
import {StaticBaseUrl} from "../Setting";
function LoginButton({type, align = "center", style = {background: "#ffffff", color: "#000000"}, activeStyle = {background: "#ededee"}}) {
function LoginButton({type, logoUrl, align = "center", style = {background: "#ffffff", color: "#000000"}, activeStyle = {background: "#ededee"}}) {
function Icon({width = 24, height = 24, color}) {
return <img src={`${StaticBaseUrl}/buttons/${type.toLowerCase()}.svg`} alt={`Sign in with ${type}`} style={{width: width, height: height}} />;
return <img src={logoUrl} alt={`Sign in with ${type}`} style={{width: width, height: height}} />;
}
const config = {
text: `Sign in with ${type}`,

View File

@ -24,12 +24,13 @@ import * as Provider from "./Provider";
import * as ProviderButton from "./ProviderButton";
import * as Util from "./Util";
import * as Setting from "../Setting";
import * as AgreementModal from "../common/modal/AgreementModal";
import SelfLoginButton from "./SelfLoginButton";
import i18next from "i18next";
import CustomGithubCorner from "../CustomGithubCorner";
import CustomGithubCorner from "../common/CustomGithubCorner";
import {SendCodeInput} from "../common/SendCodeInput";
import SelectLanguageBox from "../SelectLanguageBox";
import {CaptchaModal} from "../common/CaptchaModal";
import LanguageSelect from "../common/select/LanguageSelect";
import {CaptchaModal} from "../common/modal/CaptchaModal";
import RedirectForm from "../common/RedirectForm";
class LoginPage extends React.Component {
@ -135,12 +136,6 @@ class LoginPage extends React.Component {
ApplicationBackend.getApplication("admin", this.state.applicationName)
.then((application) => {
this.onUpdateApplication(application);
if (application !== null && application !== undefined) {
Setting.getTermsOfUseContent(application.termsOfUse, res => {
this.setState({termsOfUseContent: res});
});
}
});
} else {
OrganizationBackend.getDefaultApplication("admin", this.state.owner)
@ -151,12 +146,6 @@ class LoginPage extends React.Component {
this.setState({
applicationName: res.data.name,
});
if (application !== null && application !== undefined) {
Setting.getTermsOfUseContent(application.termsOfUse, res => {
this.setState({termsOfUseContent: res});
});
}
} else {
this.onUpdateApplication(null);
Setting.showMessage("error", res.msg);
@ -470,25 +459,17 @@ class LoginPage extends React.Component {
this.renderPasswordOrCodeInput()
}
</Row>
<Form.Item>
{
Setting.isAgreementRequired(application) ?
Setting.renderAgreement(true, () => {
this.setState({
isTermsOfUseVisible: true,
});
}, true, {}, Setting.isDefaultTrue(application)) : (
<Form.Item name="autoSignin" valuePropName="checked" noStyle>
<Checkbox style={{float: "left"}} disabled={!application.enablePassword}>
{i18next.t("login:Auto sign in")}
</Checkbox>
</Form.Item>
)
}
<div style={{display: "inline-flex", justifyContent: "space-between", width: "320px", marginBottom: AgreementModal.isAgreementRequired(application) ? "5px" : "25px"}}>
<Form.Item name="autoSignin" valuePropName="checked" noStyle>
<Checkbox style={{float: "left"}} disabled={!application.enablePassword}>
{i18next.t("login:Auto sign in")}
</Checkbox>
</Form.Item>
{
Setting.renderForgetLink(application, i18next.t("login:Forgot password?"))
}
</Form.Item>
</div>
{AgreementModal.isAgreementRequired(application) ? AgreementModal.renderAgreementFormItem(application, true, {}, this) : null}
<Form.Item>
<Button
type="primary"
@ -833,26 +814,13 @@ class LoginPage extends React.Component {
{
Setting.renderLogo(application)
}
<SelectLanguageBox languages={application.organizationObj.languages} style={{top: "55px", right: "5px", position: "absolute"}} />
<LanguageSelect languages={application.organizationObj.languages} style={{top: "55px", right: "5px", position: "absolute"}} />
{
this.renderSignedInBox()
}
{
this.renderForm(application)
}
{
Setting.renderModal(this.state.isTermsOfUseVisible, () => {
this.form.current.setFieldsValue({agreement: true});
this.setState({
isTermsOfUseVisible: false,
});
}, () => {
this.form.current.setFieldsValue({agreement: false});
this.setState({
isTermsOfUseVisible: false,
});
}, this.state.termsOfUseContent)
}
</div>
</div>
</div>

View File

@ -19,9 +19,9 @@ import * as UserBackend from "../backend/UserBackend";
import * as AuthBackend from "./AuthBackend";
import * as Setting from "../Setting";
import i18next from "i18next";
import AffiliationSelect from "../common/AffiliationSelect";
import AffiliationSelect from "../common/select/AffiliationSelect";
import OAuthWidget from "../common/OAuthWidget";
import SelectRegionBox from "../SelectRegionBox";
import RegionSelect from "../common/select/RegionSelect";
import {withRouter} from "react-router-dom";
class PromptPage extends React.Component {
@ -151,7 +151,7 @@ class PromptPage extends React.Component {
</span>
</Col>
<Col >
<SelectRegionBox defaultValue={this.state.user.region} onChange={(value) => {
<RegionSelect defaultValue={this.state.user.region} onChange={(value) => {
this.updateUserFieldWithoutSubmit("region", value);
}} />
</Col>

View File

@ -44,62 +44,62 @@ import * as AuthBackend from "./AuthBackend";
import {getEvent} from "./Util";
import {Modal} from "antd";
function getSigninButton(type) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", type);
if (type === "GitHub") {
function getSigninButton(provider) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", provider.type);
if (provider.type === "GitHub") {
return <GithubLoginButton text={text} align={"center"} />;
} else if (type === "Google") {
} else if (provider.type === "Google") {
return <GoogleLoginButton text={text} align={"center"} />;
} else if (type === "QQ") {
} else if (provider.type === "QQ") {
return <QqLoginButton text={text} align={"center"} />;
} else if (type === "Facebook") {
} else if (provider.type === "Facebook") {
return <FacebookLoginButton text={text} align={"center"} />;
} else if (type === "Weibo") {
} else if (provider.type === "Weibo") {
return <WeiboLoginButton text={text} align={"center"} />;
} else if (type === "Gitee") {
} else if (provider.type === "Gitee") {
return <GiteeLoginButton text={text} align={"center"} />;
} else if (type === "WeChat") {
} else if (provider.type === "WeChat") {
return <WechatLoginButton text={text} align={"center"} />;
} else if (type === "DingTalk") {
} else if (provider.type === "DingTalk") {
return <DingTalkLoginButton text={text} align={"center"} />;
} else if (type === "LinkedIn") {
} else if (provider.type === "LinkedIn") {
return <LinkedInLoginButton text={text} align={"center"} />;
} else if (type === "WeCom") {
} else if (provider.type === "WeCom") {
return <WeComLoginButton text={text} align={"center"} />;
} else if (type === "Lark") {
} else if (provider.type === "Lark") {
return <LarkLoginButton text={text} align={"center"} />;
} else if (type === "GitLab") {
} else if (provider.type === "GitLab") {
return <GitLabLoginButton text={text} align={"center"} />;
} else if (type === "Adfs") {
} else if (provider.type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} />;
} else if (type === "Casdoor") {
} else if (provider.type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />;
} else if (type === "Baidu") {
} else if (provider.type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} />;
} else if (type === "Alipay") {
} else if (provider.type === "Alipay") {
return <AlipayLoginButton text={text} align={"center"} />;
} else if (type === "Infoflow") {
} else if (provider.type === "Infoflow") {
return <InfoflowLoginButton text={text} align={"center"} />;
} else if (type === "Apple") {
} else if (provider.type === "Apple") {
return <AppleLoginButton text={text} align={"center"} />;
} else if (type === "AzureAD") {
} else if (provider.type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (type === "Slack") {
} else if (provider.type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (type === "Steam") {
} else if (provider.type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />;
} else if (type === "Bilibili") {
} else if (provider.type === "Bilibili") {
return <BilibiliLoginButton text={text} align={"center"} />;
} else if (type === "Okta") {
} else if (provider.type === "Okta") {
return <OktaLoginButton text={text} align={"center"} />;
} else if (type === "Douyin") {
} else if (provider.type === "Douyin") {
return <DouyinLoginButton text={text} align={"center"} />;
} else {
return <LoginButton key={type} type={type} />;
return <LoginButton key={provider.type} type={provider.type} logoUrl={getProviderLogoURL(provider)} />;
}
}
function getSamlUrl(provider, location) {
function goToSamlUrl(provider, location) {
const params = new URLSearchParams(location.search);
const clientId = params.get("client_id") ?? "";
const state = params.get("state");
@ -149,12 +149,11 @@ export function renderProviderLogo(provider, application, width, margin, size, l
}
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={() => getSamlUrl(provider, location)}>
<a key={provider.displayName} onClick={() => goToSamlUrl(provider, location)}>
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
}
} else if (provider.type === "Custom") {
// style definition
const text = i18next.t("login:Sign in with {type}").replace("{type}", provider.displayName);
@ -173,7 +172,7 @@ export function renderProviderLogo(provider, application, width, margin, size, l
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={() => getSamlUrl(provider, location)} style={customAStyle}>
<a key={provider.displayName} onClick={() => goToSamlUrl(provider, location)} style={customAStyle}>
<button style={customButtonStyle}>
<img width={26} src={getProviderLogoURL(provider)} alt={provider.displayName} style={customImgStyle} />
<span style={customSpanStyle}>{text}</span>
@ -182,14 +181,27 @@ export function renderProviderLogo(provider, application, width, margin, size, l
);
}
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
getSigninButton(provider.type)
}
</a>
</div>
);
// big button, for disable password signin
if (provider.category === "SAML") {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a onClick={() => goToSamlUrl(provider, location)}>
{
getSigninButton(provider)
}
</a>
</div>
);
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
getSigninButton(provider)
}
</a>
</div>
);
}
}
}

View File

@ -21,12 +21,13 @@ import i18next from "i18next";
import * as Util from "./Util";
import {authConfig} from "./Auth";
import * as ApplicationBackend from "../backend/ApplicationBackend";
import * as AgreementModal from "../common/modal/AgreementModal";
import {SendCodeInput} from "../common/SendCodeInput";
import SelectRegionBox from "../SelectRegionBox";
import CustomGithubCorner from "../CustomGithubCorner";
import SelectLanguageBox from "../SelectLanguageBox";
import RegionSelect from "../common/select/RegionSelect";
import CustomGithubCorner from "../common/CustomGithubCorner";
import LanguageSelect from "../common/select/LanguageSelect";
import {withRouter} from "react-router-dom";
import {CountryCodeSelect} from "../common/CountryCodeSelect";
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
const formItemLayout = {
labelCol: {
@ -47,7 +48,7 @@ const formItemLayout = {
},
};
const tailFormItemLayout = {
export const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
@ -105,12 +106,6 @@ class SignupPage extends React.Component {
ApplicationBackend.getApplication("admin", applicationName)
.then((application) => {
this.onUpdateApplication(application);
if (application !== null && application !== undefined) {
Setting.getTermsOfUseContent(application.termsOfUse, res => {
this.setState({termsOfUseContent: res});
});
}
});
}
@ -311,7 +306,7 @@ class SignupPage extends React.Component {
},
]}
>
<SelectRegionBox onChange={(value) => {this.setState({region: value});}} />
<RegionSelect onChange={(value) => {this.setState({region: value});}} />
</Form.Item>
);
} else if (signupItem.name === "Email") {
@ -391,11 +386,11 @@ class SignupPage extends React.Component {
},
({getFieldValue}) => ({
validator: (_, value) => {
if (!required && value === "") {
if (!required && !value) {
return Promise.resolve();
}
if (value !== "" && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
if (value && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
this.setState({validPhone: false});
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
}
@ -477,32 +472,10 @@ class SignupPage extends React.Component {
</Form.Item>
);
} else if (signupItem.name === "Agreement") {
return (
Setting.renderAgreement(Setting.isAgreementRequired(application), () => {
this.setState({
isTermsOfUseVisible: true,
});
}, false, tailFormItemLayout, Setting.isDefaultTrue(application))
);
return AgreementModal.renderAgreementFormItem(application, required, tailFormItemLayout, this);
}
}
renderModal() {
return (
Setting.renderModal(this.state.isTermsOfUseVisible, () => {
this.form.current.setFieldsValue({agreement: true});
this.setState({
isTermsOfUseVisible: false,
});
}, () => {
this.form.current.setFieldsValue({agreement: false});
this.setState({
isTermsOfUseVisible: false,
});
}, this.state.termsOfUseContent)
);
}
renderForm(application) {
if (!application.enableSignUp) {
return (
@ -615,16 +588,13 @@ class SignupPage extends React.Component {
{
Setting.renderLogo(application)
}
<SelectLanguageBox languages={application.organizationObj.languages} style={{top: "55px", right: "5px", position: "absolute"}} />
<LanguageSelect languages={application.organizationObj.languages} style={{top: "55px", right: "5px", position: "absolute"}} />
{
this.renderForm(application)
}
</div>
</div>
</div>
{
this.renderModal()
}
</React.Fragment>
);
}

View File

@ -43,21 +43,20 @@ export function renderMessage(msg) {
export function renderMessageLarge(ths, msg) {
if (msg !== null) {
return (
<div style={{display: "inline"}}>
<Result
status="error"
title="There was a problem signing you in.."
subTitle={msg}
extra={[
<Button type="primary" key="back" onClick={() => {
window.history.go(-2);
}}>
<Result
style={{margin: "0px auto"}}
status="error"
title="There was a problem signing you in.."
subTitle={msg}
extra={[
<Button type="primary" key="back" onClick={() => {
window.history.go(-2);
}}>
Back
</Button>,
]}
>
</Result>
</div>
</Button>,
]}
>
</Result>
);
} else {
return null;

View File

@ -55,11 +55,10 @@ export function getUserApplication(owner, name) {
}
export function updateApplication(owner, name, application) {
const newApplication = Setting.deepCopy(application);
return fetch(`${Setting.ServerUrl}/api/update-application?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newApplication),
body: JSON.stringify(application),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},

View File

@ -15,7 +15,7 @@
import {Button} from "antd";
import React from "react";
import i18next from "i18next";
import {CaptchaModal} from "./CaptchaModal";
import {CaptchaModal} from "./modal/CaptchaModal";
import * as UserBackend from "../backend/UserBackend";
export const CaptchaPreview = (props) => {

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import * as Conf from "./Conf";
import * as Conf from "../Conf";
import GithubCorner from "react-github-corner";
class CustomGithubCorner extends React.Component {

View File

@ -17,7 +17,7 @@ import React from "react";
import i18next from "i18next";
import * as UserBackend from "../backend/UserBackend";
import {SafetyOutlined} from "@ant-design/icons";
import {CaptchaModal} from "./CaptchaModal";
import {CaptchaModal} from "./modal/CaptchaModal";
const {Search} = Input;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
export function sendTestEmail(provider, email) {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
export function sendTestSms(provider, phone) {

View File

@ -0,0 +1,126 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Checkbox, Form, Modal} from "antd";
import i18next from "i18next";
import React, {useEffect, useState} from "react";
export const AgreementModal = (props) => {
const {open, onOk, onCancel, application} = props;
const [doc, setDoc] = useState("");
useEffect(() => {
getTermsOfUseContent(application.termsOfUseUrl).then((data) => {
setDoc(data);
});
}, []);
return (
<Modal
title={i18next.t("signup:Terms of Use")}
open={open}
width={"55vw"}
closable={false}
okText={i18next.t("signup:Accept")}
cancelText={i18next.t("signup:Decline")}
onOk={onOk}
onCancel={onCancel}
>
<iframe title={"terms"} style={{border: 0, width: "100%", height: "60vh"}} srcDoc={doc} />
</Modal>
);
};
function getTermsOfUseContent(url) {
return fetch(url, {
method: "GET",
}).then(r => r.text());
}
export function isAgreementRequired(application) {
if (application) {
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
if (!agreementItem || agreementItem.rule === "None" || !agreementItem.rule) {
return false;
}
if (agreementItem.required) {
return true;
}
}
return false;
}
function initDefaultValue(application) {
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
return isAgreementRequired(application) && agreementItem.rule === "Signin (Default True)";
}
export function renderAgreementFormItem(application, required, layout, ths) {
return (<React.Fragment>
<Form.Item
name="agreement"
key="agreement"
valuePropName="checked"
rules={[
{
required: required,
},
() => ({
validator: (_, value) => {
if (!required) {
return Promise.resolve();
}
if (!value) {
return Promise.reject(i18next.t("signup:Please accept the agreement!"));
} else {
return Promise.resolve();
}
},
}),
]
}
{...layout}
initialValue={initDefaultValue(application)}
>
<Checkbox style={{float: "left"}}>
{i18next.t("signup:Accept")}&nbsp;
<a onClick={() => {
ths.setState({
isTermsOfUseVisible: true,
});
}}
>
{i18next.t("signup:Terms of Use")}
</a>
</Checkbox>
</Form.Item>
<AgreementModal application={application} layout={layout} open={ths.state.isTermsOfUseVisible}
onOk={() => {
ths.form.current.setFieldsValue({agreement: true});
ths.setState({
isTermsOfUseVisible: false,
});
}}
onCancel={() => {
ths.form.current.setFieldsValue({agreement: false});
ths.setState({
isTermsOfUseVisible: false,
});
}} />
</React.Fragment>
);
}

View File

@ -15,8 +15,8 @@
import {Button, Col, Input, Modal, Row} from "antd";
import i18next from "i18next";
import React, {useEffect} from "react";
import * as UserBackend from "../backend/UserBackend";
import {CaptchaWidget} from "./CaptchaWidget";
import * as UserBackend from "../../backend/UserBackend";
import {CaptchaWidget} from "../CaptchaWidget";
import {SafetyOutlined} from "@ant-design/icons";
export const CaptchaModal = (props) => {

View File

@ -15,12 +15,12 @@
import React, {useEffect, useState} from "react";
import Cropper from "react-cropper";
import "cropperjs/dist/cropper.css";
import * as Setting from "./Setting";
import * as Setting from "../../Setting";
import {Button, Col, Modal, Row, Select} from "antd";
import i18next from "i18next";
import * as ResourceBackend from "./backend/ResourceBackend";
import * as ResourceBackend from "../../backend/ResourceBackend";
export const CropperDiv = (props) => {
export const CropperDivModal = (props) => {
const [loading, setLoading] = useState(true);
const [options, setOptions] = useState([]);
const [image, setImage] = useState("");
@ -60,7 +60,7 @@ export const CropperDiv = (props) => {
// Setting.showMessage("success", "uploading...");
const extension = image.substring(image.indexOf("/") + 1, image.indexOf(";base64"));
const fullFilePath = `avatar/${user.owner}/${user.name}.${extension}`;
ResourceBackend.uploadResource(user.owner, user.name, "avatar", "CropperDiv", fullFilePath, blob)
ResourceBackend.uploadResource(user.owner, user.name, "avatar", "CropperDivModal", fullFilePath, blob)
.then((res) => {
if (res.status === "ok") {
window.location.href = window.location.pathname;
@ -187,4 +187,4 @@ export const CropperDiv = (props) => {
);
};
export default CropperDiv;
export default CropperDivModal;

View File

@ -15,8 +15,8 @@
import {Button, Col, Input, Modal, Row} from "antd";
import i18next from "i18next";
import React from "react";
import * as UserBackend from "./backend/UserBackend";
import * as Setting from "./Setting";
import * as UserBackend from "../../backend/UserBackend";
import * as Setting from "../../Setting";
export const PasswordModal = (props) => {
const [visible, setVisible] = React.useState(false);

View File

@ -15,9 +15,9 @@
import {Button, Col, Input, Modal, Row} from "antd";
import i18next from "i18next";
import React from "react";
import * as Setting from "./Setting";
import * as UserBackend from "./backend/UserBackend";
import {SendCodeInput} from "./common/SendCodeInput";
import * as Setting from "../../Setting";
import * as UserBackend from "../../backend/UserBackend";
import {SendCodeInput} from "../SendCodeInput";
import {MailOutlined, PhoneOutlined} from "@ant-design/icons";
export const ResetModal = (props) => {

View File

@ -1,119 +1,119 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Cascader, Col, Input, Row, Select} from "antd";
import i18next from "i18next";
import * as UserBackend from "../backend/UserBackend";
import * as Setting from "../Setting";
class AffiliationSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
addressOptions: [],
affiliationOptions: [],
};
}
UNSAFE_componentWillMount() {
this.getAddressOptions(this.props.application);
this.getAffiliationOptions(this.props.application, this.props.user);
}
getAddressOptions(application) {
if (application.affiliationUrl === "") {
return;
}
const addressUrl = application.affiliationUrl.split("|")[0];
UserBackend.getAddressOptions(addressUrl)
.then((addressOptions) => {
this.setState({
addressOptions: addressOptions,
});
});
}
getAffiliationOptions(application, user) {
if (application.affiliationUrl === "") {
return;
}
const affiliationUrl = application.affiliationUrl.split("|")[1];
const code = user.address[user.address.length - 1];
UserBackend.getAffiliationOptions(affiliationUrl, code)
.then((affiliationOptions) => {
this.setState({
affiliationOptions: affiliationOptions,
});
});
}
updateUserField(key, value) {
this.props.onUpdateUserField(key, value);
}
render() {
return (
<React.Fragment>
{
this.props.application?.affiliationUrl === "" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{Setting.getLabel(i18next.t("user:Address"), i18next.t("user:Address - Tooltip"))} :
</Col>
<Col span={24 - this.props.labelSpan} >
<Cascader style={{width: "100%", maxWidth: "400px"}} value={this.props.user.address} options={this.state.addressOptions} onChange={value => {
this.updateUserField("address", value);
this.updateUserField("affiliation", "");
this.updateUserField("score", 0);
this.getAffiliationOptions(this.props.application, this.props.user);
}} placeholder={i18next.t("signup:Please input your address!")} />
</Col>
</Row>
)
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{Setting.getLabel(i18next.t("user:Affiliation"), i18next.t("user:Affiliation - Tooltip"))} :
</Col>
<Col span={22} >
{
this.props.application?.affiliationUrl === "" ? (
<Input value={this.props.user.affiliation} onChange={e => {
this.updateUserField("affiliation", e.target.value);
}} />
) : (
<Select virtual={false} style={{width: "100%"}} value={this.props.user.affiliation}
onChange={(value => {
const name = value;
const affiliationOption = Setting.getArrayItem(this.state.affiliationOptions, "name", name);
const id = affiliationOption.id;
this.updateUserField("affiliation", name);
this.updateUserField("score", id);
})}
options={[Setting.getOption(`(${i18next.t("general:empty")})`, "")].concat(this.state.affiliationOptions.map((affiliationOption) => Setting.getOption(affiliationOption.name, affiliationOption.name))
)} />
)
}
</Col>
</Row>
</React.Fragment>
);
}
}
export default AffiliationSelect;
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Cascader, Col, Input, Row, Select} from "antd";
import i18next from "i18next";
import * as UserBackend from "../../backend/UserBackend";
import * as Setting from "../../Setting";
class AffiliationSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
addressOptions: [],
affiliationOptions: [],
};
}
componentDidMount() {
this.getAddressOptions(this.props.application);
this.getAffiliationOptions(this.props.application, this.props.user);
}
getAddressOptions(application) {
if (application.affiliationUrl === "") {
return;
}
const addressUrl = application.affiliationUrl.split("|")[0];
UserBackend.getAddressOptions(addressUrl)
.then((addressOptions) => {
this.setState({
addressOptions: addressOptions,
});
});
}
getAffiliationOptions(application, user) {
if (application.affiliationUrl === "") {
return;
}
const affiliationUrl = application.affiliationUrl.split("|")[1];
const code = user.address[user.address.length - 1];
UserBackend.getAffiliationOptions(affiliationUrl, code)
.then((affiliationOptions) => {
this.setState({
affiliationOptions: affiliationOptions,
});
});
}
updateUserField(key, value) {
this.props.onUpdateUserField(key, value);
}
render() {
return (
<React.Fragment>
{
this.props.application?.affiliationUrl === "" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{Setting.getLabel(i18next.t("user:Address"), i18next.t("user:Address - Tooltip"))} :
</Col>
<Col span={24 - this.props.labelSpan} >
<Cascader style={{width: "100%", maxWidth: "400px"}} value={this.props.user.address} options={this.state.addressOptions} onChange={value => {
this.updateUserField("address", value);
this.updateUserField("affiliation", "");
this.updateUserField("score", 0);
this.getAffiliationOptions(this.props.application, this.props.user);
}} placeholder={i18next.t("signup:Please input your address!")} />
</Col>
</Row>
)
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{Setting.getLabel(i18next.t("user:Affiliation"), i18next.t("user:Affiliation - Tooltip"))} :
</Col>
<Col span={22} >
{
this.props.application?.affiliationUrl === "" ? (
<Input value={this.props.user.affiliation} onChange={e => {
this.updateUserField("affiliation", e.target.value);
}} />
) : (
<Select virtual={false} style={{width: "100%"}} value={this.props.user.affiliation}
onChange={(value => {
const name = value;
const affiliationOption = Setting.getArrayItem(this.state.affiliationOptions, "name", name);
const id = affiliationOption.id;
this.updateUserField("affiliation", name);
this.updateUserField("score", id);
})}
options={[Setting.getOption(`(${i18next.t("general:empty")})`, "")].concat(this.state.affiliationOptions.map((affiliationOption) => Setting.getOption(affiliationOption.name, affiliationOption.name))
)} />
)
}
</Col>
</Row>
</React.Fragment>
);
}
}
export default AffiliationSelect;

View File

@ -13,7 +13,7 @@
// limitations under the License.
import {Select} from "antd";
import * as Setting from "../Setting";
import * as Setting from "../../Setting";
import React from "react";
export const CountryCodeSelect = (props) => {

View File

@ -13,9 +13,9 @@
// limitations under the License.
import React from "react";
import * as Setting from "./Setting";
import * as Setting from "../../Setting";
import {Dropdown} from "antd";
import "./App.less";
import "../../App.less";
import {GlobalOutlined} from "@ant-design/icons";
function flagIcon(country, alt) {
@ -24,7 +24,7 @@ function flagIcon(country, alt) {
);
}
class SelectLanguageBox extends React.Component {
class LanguageSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
@ -63,4 +63,4 @@ class SelectLanguageBox extends React.Component {
}
}
export default SelectLanguageBox;
export default LanguageSelect;

View File

@ -13,12 +13,12 @@
// limitations under the License.
import React from "react";
import * as Setting from "./Setting";
import * as Setting from "../../Setting";
import {Select} from "antd";
const {Option} = Select;
class SelectRegionBox extends React.Component {
class RegionSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
@ -59,4 +59,4 @@ class SelectRegionBox extends React.Component {
}
}
export default SelectRegionBox;
export default RegionSelect;

View File

@ -13,9 +13,9 @@
// limitations under the License.
import React from "react";
import * as Setting from "./Setting";
import * as Setting from "../../Setting";
import {Dropdown} from "antd";
import "./App.less";
import "../../App.less";
import i18next from "i18next";
import {CheckOutlined} from "@ant-design/icons";
import {CompactTheme, DarkTheme, Light} from "antd-token-previewer/es/icons";
@ -34,7 +34,7 @@ function getIcon(themeKey) {
}
}
class SelectThemeBox extends React.Component {
class ThemeSelect extends React.Component {
constructor(props) {
super(props);
}
@ -91,4 +91,4 @@ class SelectThemeBox extends React.Component {
}
}
export default SelectThemeBox;
export default ThemeSelect;

View File

@ -1,110 +1,110 @@
{
"account": {
"Logout": "Abmeldung",
"Logout": "Abmelden",
"My Account": "Mein Konto",
"Sign Up": "Anmeldung"
"Sign Up": "Anmelden"
},
"adapter": {
"Duplicated policy rules": "Doppelte Richtlinienregeln",
"Edit Adapter": "Bearbeiten Sie den Adapter",
"Failed to sync policies": "Fehler beim Synchronisieren von Richtlinien",
"Edit Adapter": "Adapter bearbeiten",
"Failed to sync policies": "Fehler beim Synchronisieren der Richtlinien",
"New Adapter": "Neuer Adapter",
"Policies": "Richtlinien",
"Policies - Tooltip": "Casbin-Richtlinienregeln",
"Sync policies successfully": "Synchronisierungspolitiken erfolgreich umgesetzt"
"Policies - Tooltip": "Casbin Richtlinienregeln",
"Sync policies successfully": "Richtlinien synchronisiert"
},
"application": {
"Always": "Immer",
"Auto signin": "Automatische Anmeldung",
"Auto signin - Tooltip": "Wenn eine angemeldete Sitzung in Casdoor vorhanden ist, wird sie automatisch für die Anmeldung auf Anwendungsebene verwendet",
"Background URL": "Hintergrund-URL",
"Background URL - Tooltip": "URL des Hintergrundbildes, das auf der Anmeldeseite verwendet wird",
"Auto signin - Tooltip": "Wenn eine angemeldete Session in Casdoor vorhanden ist, wird diese automatisch für die Anmeldung auf Anwendungsebene verwendet",
"Background URL": "Background-URL",
"Background URL - Tooltip": "URL des Hintergrundbildes, das auf der Anmeldeseite angezeigt wird",
"Center": "Zentrum",
"Copy SAML metadata URL": "Kopieren Sie die SAML-Metadaten-URL",
"Copy prompt page URL": "Kopiere die URL der Prompt-Seite",
"Copy signin page URL": "Kopieren Sie die URL der Anmeldeseite",
"Copy signup page URL": "Kopieren Sie die URL der Anmeldeseite",
"Edit Application": "Bearbeitungsanwendung",
"Copy SAML metadata URL": "SAML-Metadaten-URL kopieren",
"Copy prompt page URL": "URL der Prompt-Seite kopieren",
"Copy signin page URL": "URL der Anmeldeseite kopieren",
"Copy signup page URL": "URL der Anmeldeseite kopieren",
"Edit Application": "Anwendung bearbeiten",
"Enable Email linking": "E-Mail-Verknüpfung aktivieren",
"Enable Email linking - Tooltip": "Bei der Verwendung von 3rd-Party-Anbietern zur Anmeldung wird, wenn es in der Organisation einen Benutzer mit der gleichen E-Mail gibt, automatisch die 3rd-Party-Anmelde-Methode mit diesem Benutzer verbunden",
"Enable SAML compression": "Aktivieren Sie SAML-Komprimierung",
"Enable Email linking - Tooltip": "Bei der Verwendung von Drittanbietern zur Anmeldung wird, wenn es in der Organisation einen Benutzer mit der gleichen E-Mail gibt, automatisch die Drittanbieter-Anmelde-Methode mit diesem Benutzer verbunden",
"Enable SAML compression": "SAML-Komprimierung aktivieren",
"Enable SAML compression - Tooltip": "Ob SAML-Antwortnachrichten komprimiert werden sollen, wenn Casdoor als SAML-IdP verwendet wird",
"Enable WebAuthn signin": "Aktivieren Sie die Anmeldung mit WebAuthn",
"Enable WebAuthn signin": "Anmeldung mit WebAuthn aktivieren",
"Enable WebAuthn signin - Tooltip": "Ob Benutzern erlaubt werden soll, sich mit WebAuthn anzumelden",
"Enable code signin": "Aktivieren Sie die Code-Unterzeichnung",
"Enable code signin - Tooltip": "Ob Benutzern erlaubt werden soll, sich mit einer Telefon- oder E-Mail-Bestätigungscode anzumelden",
"Enable password": "Aktiviere das Passwort",
"Enable code signin": "Code Anmeldung aktivieren",
"Enable code signin - Tooltip": "Ob Benutzern erlaubt werden soll, sich mit einem Telefon- oder E-Mail-Bestätigungscode anzumelden",
"Enable password": "Passwort aktivieren",
"Enable password - Tooltip": "Ob Benutzern erlaubt werden soll, sich mit einem Passwort anzumelden",
"Enable side panel": "Aktiviere die Seitenleiste",
"Enable side panel": "Sidepanel aktivieren",
"Enable signin session - Tooltip": "Ob Casdoor eine Sitzung aufrechterhält, nachdem man sich von der Anwendung aus bei Casdoor angemeldet hat",
"Enable signup": "Aktivieren Sie die Registrierung",
"Enable signup": "Registrierung aktivieren",
"Enable signup - Tooltip": "Ob Benutzern erlaubt werden soll, ein neues Konto zu registrieren",
"Failed to sign in": "Fehler bei der Anmeldung",
"File uploaded successfully": "Datei erfolgreich hochgeladen",
"Follow organization theme": "Folge dem Thema der Organisation",
"Form CSS": "Formular CSS",
"Form CSS - Edit": "Formular CSS - Bearbeiten",
"Form CSS - Tooltip": "CSS-Styling der Anmelde-, Registrierungs- und Passwort-vergessen-Formulare (z. B. Hinzufügen von Rahmen und Schatten)",
"Follow organization theme": "Folge dem Theme der Organisation",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Bearbeiten",
"Form CSS - Tooltip": "CSS-Styling der Anmelde-, Registrierungs- und Passwort-vergessen-Seite (z. B. Hinzufügen von Rahmen und Schatten)",
"Form position": "Formposition",
"Form position - Tooltip": "Ort der Anmelde-, Anmelde- und Passwort vergessen-Formulare",
"Form position - Tooltip": "Position der Anmelde-, Registrierungs- und Passwort-vergessen-Formulare",
"Grant types": "Grant-Typen",
"Grant types - Tooltip": "Wählen Sie aus, welche Förderarten im OAuth-Protokoll zulässig sind",
"Grant types - Tooltip": "Wählen Sie aus, welche Grant-Typen im OAuth-Protokoll zulässig sind",
"Left": "Links",
"Logged in successfully": "Erfolgreich eingeloggt",
"Logged out successfully": "Erfolgreich ausgeloggt",
"New Application": "Neue Anwendung",
"None": "kein",
"Please input your application!": "Bitte geben Sie Ihre Bewerbung ein!",
"None": "kein(e)",
"Please input your application!": "Bitte geben Sie Ihre Anwendung ein!",
"Please input your organization!": "Bitte geben Sie Ihre Organisation ein!",
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei aus",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Die URL der Seite wurde erfolgreich in die Zwischenablage kopiert. Bitte fügen Sie sie in das Inkognito-Fenster oder einen anderen Browser ein",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Die URL der Seite wurde erfolgreich in die Zwischenablage kopiert. Bitte fügen Sie sie in einen Inkognito-Tab oder einen anderen Browser ein",
"Redirect URL": "Weiterleitungs-URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "Weiterleitungs-URL (Assertion Consumer Service POST Binding URL)",
"Redirect URLs": "Weiterleitungs-URLs",
"Redirect URLs - Tooltip": "Liste erlaubter Umleitungs-URLs mit Unterstützung von regulärer Ausdrucksprüfung; URLs, die nicht in der Liste enthalten sind, können nicht umgeleitet werden",
"Refresh token expire": "Das Auffrischen des Tokens ist abgelaufen",
"Refresh token expire - Tooltip": "Ablaufzeit des Aktualisierungstokens",
"Refresh token expire": "Gültigkeitsdauer des Refresh-Tokens",
"Refresh token expire - Tooltip": "Angabe der Gültigkeitsdauer des Refresh Tokens",
"Right": "Rechts",
"Rule": "Regel",
"SAML metadata": "SAML-Metadaten",
"SAML metadata - Tooltip": "Die Metadaten des SAML-Protokolls",
"SAML metadata URL copied to clipboard successfully": "SAML-Metadaten URL erfolgreich in die Zwischenablage kopiert",
"SAML reply URL": "SAML Antwort-URL",
"Side panel HTML": "Seitenleisten-HTML",
"Side panel HTML - Edit": "Seitenleisten HTML - Bearbeiten",
"Side panel HTML - Tooltip": "Passen Sie den HTML-Code für das Seitenfeld der Login-Seite an",
"SAML reply URL": "SAML Reply-URL",
"Side panel HTML": "Sidepanel-HTML",
"Side panel HTML - Edit": "Sidepanel HTML - Bearbeiten",
"Side panel HTML - Tooltip": "Passen Sie den HTML-Code für das Sidepanel der Login-Seite an",
"Sign Up Error": "Registrierungsfehler",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Die URL der Anmeldeseite wurde erfolgreich in die Zwischenablage kopiert. Bitte fügen Sie sie in das Inkognito-Fenster oder einen anderen Browser ein",
"Signin session": "Anmeldesitzung",
"Signup items": "Anmeldungsartikel",
"Signup items - Tooltip": "Gegenstände, die Benutzer ausfüllen müssen, wenn sie neue Konten registrieren",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Anmeldeseite-URL erfolgreich in die Zwischenablage kopiert. Bitte fügen Sie sie in das Inkognito-Fenster oder einen anderen Browser ein",
"The application does not allow to sign up new account": "Die Anwendung erlaubt es nicht, ein neues Konto anzumelden",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Die URL der Anmeldeseite wurde in die Zwischenablage kopiert. Bitte fügen Sie sie in einen Inkognito-Tab oder einen anderen Browser ein",
"Signin session": "Anmeldesession",
"Signup items": "Registrierungs Items",
"Signup items - Tooltip": "Items, die Benutzer ausfüllen müssen, wenn sie neue Konten registrieren",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Die URL der Registrierungsseite wurde in die Zwischenablage kopiert. Bitte fügen Sie sie in einen Inkognito-Tab oder einen anderen Browser ein",
"The application does not allow to sign up new account": "Die Anwendung erlaubt es nicht, ein neues Konto zu registrieren",
"Token expire": "Token läuft ab",
"Token expire - Tooltip": "Ablaufzeit des Zugriffstokens",
"Token expire - Tooltip": "Ablaufzeit des Access-Tokens",
"Token format": "Token-Format",
"Token format - Tooltip": "Das Format des Zugriffstokens",
"You are unexpected to see this prompt page": "Du bist unerwartet diese Aufforderungsseite zu sehen"
"Token format - Tooltip": "Das Format des Access-Tokens",
"You are unexpected to see this prompt page": "Sie sind unerwartet auf diese Aufforderungsseite gelangt"
},
"cert": {
"Bit size": "Bitgröße",
"Bit size - Tooltip": "Geheimschlüssellänge",
"Bit size - Tooltip": "Länge des Secret-Keys",
"Certificate": "Zertifikat",
"Certificate - Tooltip": "Öffentliches Schlüsselzertifikat, das zum Entschlüsseln der JWT-Signatur des Access Tokens verwendet wird. Dieses Zertifikat muss normalerweise auf der Casdoor SDK-Seite (d. h. der Anwendung) bereitgestellt werden, um das JWT zu analysieren",
"Certificate copied to clipboard successfully": "Zertifikat erfolgreich in die Zwischenablage kopiert",
"Certificate - Tooltip": "Public-Key-Zertifikat, das zum Entschlüsseln der JWT-Signatur des Access Tokens verwendet wird. Dieses Zertifikat muss normalerweise auf der Casdoor SDK-Seite (d. h. der Anwendung) bereitgestellt werden, um das JWT zu parsen",
"Certificate copied to clipboard successfully": "Zertifikat in die Zwischenablage kopiert",
"Copy certificate": "Kopieren Sie das Zertifikat",
"Copy private key": "Privaten Schlüssel kopieren",
"Copy private key": "Private-Key kopieren",
"Crypto algorithm": "Kryptoalgorithmus",
"Crypto algorithm - Tooltip": "Verschlüsselungsalgorithmus, der vom Zertifikat verwendet wird",
"Download certificate": "Zertifikat herunterladen",
"Download private key": "Privater Schlüssel herunterladen",
"Download private key": "Private-Key herunterladen",
"Edit Cert": "Edit Cert - Zertifikat bearbeiten",
"Expire in years": "Verfallen in Jahren",
"Expire in years": "Ablaufzeit in Jahren",
"Expire in years - Tooltip": "Gültigkeitsdauer des Zertifikats in Jahren",
"New Cert": "Neues Zertifikat",
"Private key": "Privater Schlüssel",
"Private key": "Private-Key",
"Private key - Tooltip": "Privater Schlüssel, der zum öffentlichen Schlüsselzertifikat gehört",
"Private key copied to clipboard successfully": "Privater Schlüssel wurde erfolgreich in die Zwischenablage kopiert",
"Private key copied to clipboard successfully": "Private-Key wurde erfolgreich in die Zwischenablage kopiert",
"Scope - Tooltip": "Nutzungsszenarien des Zertifikats",
"Type - Tooltip": "Art des Zertifikats"
},
@ -117,7 +117,7 @@
"Please input your phone verification code!": "Bitte geben Sie den Bestätigungscode Ihres Telefons ein!",
"Please input your verification code!": "Bitte geben Sie Ihren Bestätigungscode ein!",
"Send Code": "Code senden",
"Sending": "Senden",
"Sending": "Sendet",
"Submit and complete": "Einreichen und abschließen"
},
"forget": {
@ -125,7 +125,7 @@
"Change Password": "Passwort ändern",
"Choose email or phone": "Wählen Sie E-Mail oder Telefon",
"Next Step": "Nächster Schritt",
"Please input your username!": "Bitte gib deinen Benutzernamen ein!",
"Please input your username!": "Bitte geben Sie Ihren Benutzernamen ein!",
"Reset": "Zurücksetzen",
"Retrieve password": "Passwort abrufen",
"Unknown forget type": "Unbekannter Vergesslichkeitstyp",
@ -137,24 +137,24 @@
"Adapter - Tooltip": "Tabellenname des Policy Stores",
"Adapters": "Adapter",
"Add": "Hinzufügen",
"Affiliation URL": "Zugehörigkeits-URL",
"Affiliation URL": "Affiliation-URL",
"Affiliation URL - Tooltip": "Die Homepage-URL für die Zugehörigkeit",
"Application": "Bewerbung",
"Application": "Applikation",
"Applications": "Anwendungen",
"Applications that require authentication": "Anwendungen, die eine Authentifizierung erfordern",
"Avatar": "Avatar",
"Avatar - Tooltip": "Öffentliches Avatarbild für den Benutzer",
"Back Home": "Zurück zu Hause",
"Back Home": "Zurück nach Hause",
"Cancel": "Abbrechen",
"Captcha": "Captcha",
"Cert": "Zertifikat",
"Cert - Tooltip": "Das öffentliche Schlüsselzertifikat, das vom Client-SDK, das mit dieser Anwendung korrespondiert, verifiziert werden muss",
"Cert - Tooltip": "Das Public-Key-Zertifikat, das vom Client-SDK, das mit dieser Anwendung korrespondiert, verifiziert werden muss",
"Certs": "Zertifikate",
"Click to Upload": "Klicken Sie zum Hochladen",
"Client IP": "Kunden-IP",
"Client IP": "Client-IP",
"Close": "Schließen",
"Created time": "Erstellte Zeit",
"Default application": "Standardanwendung",
"Default application": "Standard Anwendung",
"Default application - Tooltip": "Standard-Anwendung für Benutzer, die direkt von der Organisationsseite registriert wurden",
"Default avatar": "Standard-Avatar",
"Default avatar - Tooltip": "Standard-Avatar, der verwendet wird, wenn neu registrierte Benutzer kein Avatar-Bild festlegen",
@ -167,16 +167,16 @@
"Edit": "Bearbeiten",
"Email": "E-Mail",
"Email - Tooltip": "Gültige E-Mail-Adresse",
"Failed to add": "Konnte nicht hinzufügen",
"Failed to add": "Fehler beim hinzufügen",
"Failed to connect to server": "Die Verbindung zum Server konnte nicht hergestellt werden",
"Failed to delete": "Konnte nicht gelöscht werden",
"Failed to save": "Konnte nicht gespeichert werden",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon Icon-URL, die auf allen Casdoor-Seiten der Organisation verwendet wird",
"Favicon - Tooltip": "Favicon-URL, die auf allen Casdoor-Seiten der Organisation verwendet wird",
"First name": "Vorname",
"Forget URL": "Vergessen Sie die URL",
"Forget URL": "Passwort vergessen URL",
"Forget URL - Tooltip": "Benutzerdefinierte URL für die \"Passwort vergessen\" Seite. Wenn nicht festgelegt, wird die standardmäßige Casdoor \"Passwort vergessen\" Seite verwendet. Wenn sie festgelegt ist, wird der \"Passwort vergessen\" Link auf der Login-Seite zu dieser URL umgeleitet",
"Found some texts still not translated? Please help us translate at": "Hast du noch einige Texte gefunden, die nicht übersetzt wurden? Bitte hilf uns beim Übersetzen",
"Found some texts still not translated? Please help us translate at": "Haben Sie noch Texte gefunden, die nicht übersetzt wurden? Bitte helfen Sie uns beim Übersetzen",
"Go to writable demo site?": "Gehe zur beschreibbaren Demo-Website?",
"Home": "Zuhause",
"Home - Tooltip": "Homepage der Anwendung",
@ -207,22 +207,22 @@
"Organizations": "Organisationen",
"Password": "Passwort",
"Password - Tooltip": "Stellen Sie sicher, dass das Passwort korrekt ist",
"Password salt": "Passworthash",
"Password salt": "Passwort-Salt",
"Password salt - Tooltip": "Zufälliger Parameter, der für die Verschlüsselung von Passwörtern verwendet wird",
"Password type": "Passworttyp",
"Password type - Tooltip": "Speicherformat von Passwörtern in der Datenbank",
"Payments": "Zahlungen",
"Permissions": "Erlaubnisse",
"Permissions": "Rechte",
"Permissions - Tooltip": "Berechtigungen, die diesem Benutzer gehören",
"Phone": "Telefon",
"Phone - Tooltip": "Telefonnummer",
"Preview": "Vorschau",
"Preview - Tooltip": "Vorschau der konfigurierten Effekte",
"Products": "Produkte",
"Provider": "Anbieter",
"Provider - Tooltip": "Zahlungsanbieter müssen konfiguriert werden, einschließlich PayPal, Alipay, WeChat Pay usw.",
"Providers": "Anbieter",
"Providers - Tooltip": "Anbieter müssen konfiguriert werden, einschließlich Anmeldung durch Drittanbieter, Objektspeicherung, Verifizierungscode usw.",
"Provider": "Provider",
"Provider - Tooltip": "Zahlungsprovider, die konfiguriert werden müssen, inkl. PayPal, Alipay, WeChat Pay usw.",
"Providers": "Provider",
"Providers - Tooltip": "Provider, die konfiguriert werden müssen, einschließlich Drittanbieter-Logins, Objektspeicherung, Verifizierungscode usw.",
"Real name": "Echter Name",
"Records": "Datensätze",
"Request URI": "Anforderungs-URI",
@ -230,9 +230,9 @@
"Roles": "Rollen",
"Roles - Tooltip": "Rollen, denen der Benutzer angehört",
"Save": "Speichern",
"Save & Exit": "Speichern und Beenden",
"Session ID": "Sitzungs-ID",
"Sessions": "Sitzungen",
"Save & Exit": "Speichern und verlassen",
"Session ID": "Session-ID",
"Sessions": "Sessions",
"Signin URL": "Anmeldungs-URL",
"Signin URL - Tooltip": "Benutzerdefinierte URL für die Anmeldeseite. Wenn sie nicht festgelegt ist, wird die standardmäßige Casdoor-Anmeldeseite verwendet. Wenn sie festgelegt ist, leiten die Anmeldelinks auf verschiedenen Casdoor-Seiten zu dieser URL um",
"Signup URL": "Anmelde-URL",
@ -241,7 +241,7 @@
"Signup application - Tooltip": "Durch welche Anwendung hat sich der Benutzer angemeldet, als er sich registriert hat?",
"Sorry, the page you visited does not exist.": "Entschuldigung, die von Ihnen besuchte Seite existiert nicht.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Entschuldigung, der von Ihnen besuchte Benutzer existiert nicht oder Sie sind nicht autorisiert, auf diesen Benutzer zuzugreifen.",
"Sorry, you do not have permission to access this page or logged in status invalid.": "Es tut uns leid, aber Sie haben keine Berechtigung, auf diese Seite zuzugreifen, oder Ihr angemeldeter Status ist ungültig.",
"Sorry, you do not have permission to access this page or logged in status invalid.": "Es tut uns leid, aber Sie haben keine Berechtigung, auf diese Seite zuzugreifen, oder Sie sind nicht angemeldet.",
"State": "Bundesland / Staat",
"State - Tooltip": "Bundesland",
"Successfully added": "Erfolgreich hinzugefügt",
@ -249,7 +249,7 @@
"Successfully saved": "Erfolgreich gespeichert",
"Supported country codes": "Unterstützte Ländercodes",
"Supported country codes - Tooltip": "Ländercodes, die von der Organisation unterstützt werden. Diese Codes können als Präfix ausgewählt werden, wenn SMS-Verifizierungscodes gesendet werden",
"Sure to delete": "Sicher löschen (or Gesichertes Löschen)",
"Sure to delete": "Sicher zu löschen",
"Swagger": "Swagger",
"Sync": "Synchronisieren",
"Syncers": "Syncers",
@ -286,7 +286,7 @@
"Enable SSL - Tooltip": "Ob SSL aktiviert werden soll",
"Group ID": "Gruppen-ID",
"Last Sync": "Letzte Synchronisation",
"Server": "Serverh)",
"Server": "Server",
"Server host": "Server Host",
"Server host - Tooltip": "LDAP-Server-Adresse",
"Server name": "Servername",
@ -298,7 +298,7 @@
},
"login": {
"Auto sign in": "Automatische Anmeldung",
"Continue with": "Mach weiter mit",
"Continue with": "Weitermachen mit",
"Email or phone": "E-Mail oder Telefon",
"Forgot password?": "Passwort vergessen?",
"Loading": "Laden",
@ -316,30 +316,30 @@
"Signing in...": "Anmelden...",
"Successfully logged in with WebAuthn credentials": "Erfolgreich mit WebAuthn-Anmeldeinformationen angemeldet",
"The input is not valid Email or phone number!": "Die Eingabe ist keine gültige E-Mail-Adresse oder Telefonnummer!",
"To access": "Zu Zugriff",
"To access": "Zum Zugriff",
"Verification code": "Verifizierungscode",
"WebAuthn": "WebAuthn",
"sign up now": "Melde dich jetzt an",
"username, Email or phone": "Benutzername, E-Mail oder Telefon"
},
"model": {
"Edit Model": "Bearbeiten Modell",
"Edit Model": "Modell bearbeiten",
"Model text": "Modelltext",
"Model text - Tooltip": "Casbin Zugriffskontrollmodell inklusive integrierter Modelle wie ACL, RBAC, ABAC, RESTful, usw. Sie können auch benutzerdefinierte Modelle erstellen. Weitere Informationen finden Sie auf der Casbin-Website",
"New Model": "Neues Modell"
},
"organization": {
"Account items": "Kontenpositionen",
"Account items": "Konto Items",
"Account items - Tooltip": "Elemente auf der persönlichen Einstellungsseite",
"Edit Organization": "Organisation bearbeiten",
"Follow global theme": "Folge dem globalen Thema",
"Init score": "Initiale Punktzahl",
"Follow global theme": "Folge dem globalen Theme",
"Init score": "Initialer Score",
"Init score - Tooltip": "Anfangspunkte, die Benutzern bei der Registrierung vergeben werden",
"Is profile public": "Ist das Profil öffentlich?",
"Is profile public - Tooltip": "Nach der Schließung können nur globale Administratoren oder Benutzer in der gleichen Organisation auf die Profilseite des Benutzers zugreifen",
"Modify rule": "Regel ändern",
"New Organization": "Neue Organisation",
"Soft deletion": "Weiche Löschung",
"Soft deletion": "Softe Löschung",
"Soft deletion - Tooltip": "Wenn aktiviert, werden gelöschte Benutzer nicht vollständig aus der Datenbank entfernt. Stattdessen werden sie als gelöscht markiert",
"Tags": "Tags",
"Tags - Tooltip": "Sammlung von Tags, die für Benutzer zur Auswahl zur Verfügung stehen",
@ -353,8 +353,8 @@
"Currency": "Währung",
"Currency - Tooltip": "Wie USD, CNY usw.",
"Download Invoice": "Rechnung herunterladen",
"Edit Payment": "Bearbeiten Sie die Zahlung",
"Individual": "Individuum",
"Edit Payment": "Zahlung bearbeiten",
"Individual": "individuell",
"Invoice URL": "Rechnungs-URL",
"Invoice URL - Tooltip": "URL für den Download der Rechnung",
"Invoice actions": "Rechnungsaktionen",
@ -382,16 +382,16 @@
"Please carefully check your invoice information. Once the invoice is issued, it cannot be withdrawn or modified.": "Bitte prüfen Sie sorgfältig Ihre Rechnungsinformationen. Sobald die Rechnung ausgestellt wurde, kann sie nicht zurückgenommen oder geändert werden.",
"Please click the below button to return to the original website": "Bitte klicken Sie auf den unten stehenden Button, um zur ursprünglichen Website zurückzukehren",
"Please pay the order first!": "Bitte zahlen Sie zuerst die Bestellung!",
"Processing...": "Verarbeitung...",
"Processing...": "In Bearbeitung...",
"Product": "Produkt",
"Product - Tooltip": "Produktname",
"Result": "Ergebnis",
"Return to Website": "Zurück zur Website",
"The payment has failed": "Die Zahlung ist fehlgeschlagen",
"The payment is still under processing": "Die Zahlung wird immer noch bearbeitet",
"Type - Tooltip": "Zahlungsmethode, die beim Kauf des Produkts verwendet wird",
"Type - Tooltip": "Zahlungsmethode, die beim Kauf des Produkts verwendet wurde",
"You have successfully completed the payment": "Sie haben die Zahlung erfolgreich abgeschlossen",
"please wait for a few seconds...": "Bitte warten Sie einige Sekunden...",
"please wait for a few seconds...": "Bitte warten Sie ein paar Sekunden...",
"the current state is": "der aktuelle Zustand ist"
},
"permission": {
@ -399,17 +399,17 @@
"Actions - Tooltip": "Erlaubte Aktionen",
"Admin": "Admin",
"Allow": "erlauben",
"Approve time": "Zeit genehmigen",
"Approve time": "Zeit der Genehmigung",
"Approve time - Tooltip": "Die Genehmigungszeit für diese Erlaubnis",
"Approved": "Genehmigt",
"Approver": "Genehmiger",
"Approver - Tooltip": "Die Person, die die Genehmigung genehmigt hat",
"Deny": "Leugnen",
"Edit Permission": "Bearbeitungsberechtigung",
"Effect": "Wirkung",
"Effect - Tooltip": "erlauben oder ablehnen",
"Deny": "Ablehnen",
"Edit Permission": "Recht bearbeiten",
"Effect": "Effekt",
"Effect - Tooltip": "Erlauben oder ablehnen",
"New Permission": "Neue Genehmigung",
"Pending": "In Erwartung",
"Pending": "Ausstehend",
"Read": "Lesen",
"Resource type": "Ressourcentyp",
"Resource type - Tooltip": "Art der Ressource",
@ -433,8 +433,8 @@
"New Product": "Neues Produkt",
"Pay": "Zahlen",
"PayPal": "PayPal",
"Payment providers": "Zahlungsanbieter",
"Payment providers - Tooltip": "Anbieter von Zahlungsdiensten",
"Payment providers": "Zahlungsprovider",
"Payment providers - Tooltip": "Provider von Zahlungsdiensten",
"Placing order...": "Bestellung aufgeben...",
"Please provide your username in the remark": "Bitte geben Sie Ihren Benutzernamen in der Anmerkung an",
"Please scan the QR code to pay": "Bitte scannen Sie den QR-Code, um zu bezahlen",
@ -442,7 +442,7 @@
"Price - Tooltip": "Preis des Produkts",
"Quantity": "Menge",
"Quantity - Tooltip": "Menge des Produkts",
"Return URL": "Rückgabe-URL",
"Return URL": "Rückkeht-URL",
"Return URL - Tooltip": "URL für die Rückkehr nach einem erfolgreichen Kauf",
"SKU": "SKU",
"Sold": "Verkauft",
@ -450,79 +450,79 @@
"Tag - Tooltip": "Tag des Produkts",
"Test buy page..": "Testkaufseite.",
"There is no payment channel for this product.": "Es gibt keinen Zahlungskanal für dieses Produkt.",
"This product is currently not in sale.": "Dieses Produkt ist derzeit nicht im Verkauf.",
"This product is currently not in sale.": "Dieses Produkt steht derzeit nicht zum Verkauf.",
"USD": "USD",
"WeChat Pay": "WeChat Pay"
},
"provider": {
"Access key": "Zugriffsschlüssel",
"Access key": "Access-Key",
"Access key - Tooltip": "Zugriffsschlüssel",
"Agent ID": "Agenten-ID",
"Agent ID - Tooltip": "Agenten-ID",
"App ID": "App ID",
"App ID - Tooltip": "App-ID",
"App key": "App-Schlüssel",
"App key": "App-Key",
"App key - Tooltip": "App-Schlüssel",
"App secret": "App-Geheimnis",
"App secret": "App-Secret",
"AppSecret - Tooltip": "App-Geheimnis",
"Auth URL": "Auth-URL",
"Auth URL - Tooltip": "Auth-URL",
"Bucket": "Eimer",
"Bucket - Tooltip": "Name des Eimers",
"Bucket": "Bucket",
"Bucket - Tooltip": "Name des Buckets",
"Can not parse metadata": "Kann Metadaten nicht durchsuchen / auswerten",
"Can signin": "Einloggen möglich",
"Can signup": "Kann registrieren",
"Can unlink": "Entkoppeln möglich",
"Can signin": "Kann sich einloggen",
"Can signup": "Kann sich registrieren",
"Can unlink": "Entlinken möglich",
"Category": "Kategorie",
"Category - Tooltip": "Wählen Sie eine Kategorie aus",
"Channel No.": "Kanal Nr.",
"Channel No. - Tooltip": "Kanalnummer.",
"Client ID": "Kunden-ID",
"Client ID - Tooltip": "Kundennummer",
"Client ID 2": "Kunden-ID 2",
"Client ID 2 - Tooltip": "Die zweite Kundennnummer (ID)",
"Client secret": "Kunden-Geheimnis",
"Client secret - Tooltip": "Kunden-Geheimnis",
"Client secret 2": "Kunden-Geheimnis 2",
"Client secret 2 - Tooltip": "Der zweite Geheimcode für den Kunden",
"Client ID": "Client-ID",
"Client ID - Tooltip": "Client-ID",
"Client ID 2": "Client-ID 2",
"Client ID 2 - Tooltip": "Die zweite Client-ID",
"Client secret": "Client-Secret",
"Client secret - Tooltip": "Client-Geheimnis",
"Client secret 2": "Client-Secret 2",
"Client secret 2 - Tooltip": "Der zweite Client-Secret-Key",
"Copy": "Kopieren",
"Disable SSL": "SSL deaktivieren",
"Disable SSL - Tooltip": "Ob die Deaktivierung des SSL-Protokolls bei der Kommunikation mit dem STMP-Server erfolgen soll",
"Domain": "Domain",
"Domain - Tooltip": "Benutzerdefinierte Domäne für Objektspeicher",
"Edit Provider": "Anbieter bearbeiten",
"Domain - Tooltip": "Benutzerdefinierte Domain für Objektspeicher",
"Edit Provider": "Provider bearbeiten",
"Email content": "Email-Inhalt",
"Email content - Tooltip": "Inhalt der E-Mail",
"Email sent successfully": "E-Mail erfolgreich gesendet",
"Email title": "Email-Titel",
"Email title - Tooltip": "Betreff der E-Mail",
"Enable QR code": "QR-Code aktivieren",
"Enable QR code - Tooltip": "Ob Scannen von QR-Code zum Einloggen erlaubt werden soll",
"Endpoint": "Endpunkt",
"Endpoint (Intranet)": "Endpunkt (Intranet)",
"Enable QR code - Tooltip": "Ob das Scannen von QR-Codes zum Einloggen aktiviert werden soll",
"Endpoint": "Endpoint",
"Endpoint (Intranet)": "Endpoint (Intranet)",
"Host": "Host",
"Host - Tooltip": "Name des Gastgebers",
"Host - Tooltip": "Name des Hosts",
"IdP": "IdP",
"IdP certificate": "IdP-Zertifikat",
"Issuer URL": "Emittenten-URL",
"Issuer URL": "Issuer-URL",
"Issuer URL - Tooltip": "Emittenten-URL",
"Link copied to clipboard successfully": "Link wurde erfolgreich in die Zwischenablage kopiert",
"Metadata": "Metadaten",
"Metadata - Tooltip": "SAML-Metadaten",
"Method - Tooltip": "Anmeldeverfahren, QR-Code oder geräuschloser Login",
"New Provider": "Neuer Anbieter",
"Method - Tooltip": "Anmeldeverfahren, QR-Code oder Silent-Login",
"New Provider": "Neuer Provider",
"Parse": "parsen",
"Parse metadata successfully": "Metadaten erfolgreich analysiert",
"Path prefix": "Pfadpräfix",
"Path prefix - Tooltip": "Bucket-Pfad-Präfix für Objektspeicher",
"Please use WeChat and scan the QR code to sign in": "Bitte verwende WeChat und scanne den QR-Code ein, um dich anzumelden",
"Port": "Hafen",
"Please use WeChat and scan the QR code to sign in": "Bitte verwenden Sie WeChat und scanne den QR-Code ein, um dich anzumelden",
"Port": "Port",
"Port - Tooltip": "Stellen Sie sicher, dass der Port offen ist",
"Prompted": "ausgelöst",
"Provider URL": "Anbieter-URL",
"Provider URL": "Provider-URL",
"Provider URL - Tooltip": "URL zur Konfiguration des Dienstanbieters, dieses Feld dient nur als Referenz und wird in Casdoor nicht verwendet",
"Region ID": "Regions-ID",
"Region ID - Tooltip": "Regionale ID für den Dienstleister",
"Region ID - Tooltip": "Regions-ID für den Dienstleister",
"Region endpoint for Internet": "Regionsendpunkt für das Internet",
"Region endpoint for Intranet": "Regionales Endpunkt für Intranet",
"Required": "Benötigt",
@ -535,32 +535,32 @@
"SP ACS URL": "SP ACS URL",
"SP ACS URL - Tooltip": "SP ACS URL",
"SP Entity ID": "SP-Entitäts-ID",
"Scene": "Szene",
"Scene": "Scene",
"Scene - Tooltip": "Szene",
"Scope": "Umfang",
"Scope - Tooltip": "Umfang",
"Secret access key": "Geheimer Zugriffsschlüssel",
"Scope": "Scope",
"Scope - Tooltip": "Scope",
"Secret access key": "Secret-Access-Key",
"Secret access key - Tooltip": "Geheimer Zugriffsschlüssel",
"Secret key": "Geheimschlüssel",
"Secret key - Tooltip": "Vom Server verwendet, um die API des Verifizierungscodes-Anbieters für die Verifizierung aufzurufen",
"Secret key": "Secret-Key",
"Secret key - Tooltip": "Vom Server verwendet, um die API des Verifizierungscodes-Providers für die Verifizierung aufzurufen",
"Send Testing Email": "Senden Sie eine Test-E-Mail",
"Send Testing SMS": "Sende Test-SMS",
"Sign Name": "Unterschreiben Sie den Namen",
"Sign Name": "Signatur Namen",
"Sign Name - Tooltip": "Name der Signatur, die verwendet werden soll",
"Sign request": "Unterschriftsanforderung",
"Sign request - Tooltip": "Ob die Anfrage eine Unterschrift erfordert",
"Signin HTML": "Anmeldung HTML",
"Signin HTML - Edit": "Anmeldung HTML - Bearbeiten",
"Sign request": "Signaturanfrage",
"Sign request - Tooltip": "Ob die Anfrage eine Signatur erfordert",
"Signin HTML": "Anmeldungs-HTML",
"Signin HTML - Edit": "Anmeldungs-HTML - Bearbeiten",
"Signin HTML - Tooltip": "Benutzerdefiniertes HTML zur Ersetzung des Standard-Anmelde-Seitenstils",
"Signup HTML": "Anmeldung HTML",
"Signup HTML": "Registrierungs-HTML",
"Signup HTML - Edit": "Registrierung HTML - Bearbeiten",
"Signup HTML - Tooltip": "Benutzerdefiniertes HTML zur Ersetzung des Standard-Anmelde-Seitenstils",
"Site key": "Seitenschlüssel",
"Site key - Tooltip": "Site-Schlüssel",
"Signup HTML - Tooltip": "Benutzerdefiniertes HTML zur Ersetzung des Standard-Registrierungs-Seitenstils",
"Site key": "Site-Key",
"Site key - Tooltip": "Seitenschlüssel",
"Sub type": "Untertyp",
"Sub type - Tooltip": "Unterart",
"Template code": "Vorlagen-Code",
"Template code - Tooltip": "Vorlagen-Code",
"Template code": "Template-Code",
"Template code - Tooltip": "Template-Code",
"Test Email": "Test E-Mail",
"Test Email - Tooltip": "E-Mail-Adresse zum Empfangen von Test-E-Mails",
"Test SMTP Connection": "Testen Sie die SMTP-Verbindung",
@ -570,23 +570,23 @@
"Type - Tooltip": "Wählen Sie einen Typ aus",
"UserInfo URL": "UserInfo-URL",
"UserInfo URL - Tooltip": "UserInfo-URL",
"admin (Shared)": "admin (Gemeinsam)"
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Wird ausgelöst"
"Is triggered": "Ist ausgelöst"
},
"resource": {
"Copy Link": "Kopiere den Link",
"Copy Link": "Link kopieren",
"File name": "Dateiname",
"File size": "Dateigröße",
"Format": "Format",
"Parent": "Elternteil",
"Parent": "Parent",
"Upload a file...": "Hochladen einer Datei..."
},
"role": {
"Edit Role": "Rolle bearbeiten",
"New Role": "Neue Rolle",
"Sub domains": "Unterdomänen",
"Sub domains": "Subdomains",
"Sub domains - Tooltip": "In der aktuellen Rolle enthaltene Domains",
"Sub roles": "Unterrollen",
"Sub roles - Tooltip": "Rollen, die in der aktuellen Rolle enthalten sind",
@ -597,11 +597,11 @@
"Accept": "Akzeptieren",
"Agreement": "Vereinbarung",
"Confirm": "Bestätigen",
"Decline": "Abnahme",
"Decline": "Ablehnen",
"Have account?": "Haben Sie ein Konto?",
"Please accept the agreement!": "Bitte akzeptieren Sie die Vereinbarung!",
"Please click the below button to sign in": "Bitte klicken Sie auf die untenstehende Schaltfläche, um sich anzumelden",
"Please confirm your password!": "Bitte bestätige dein Passwort!",
"Please click the below button to sign in": "Bitte klicken Sie auf den untenstehenden Button, um sich anzumelden",
"Please confirm your password!": "Bitte bestätigen Sie Ihr Passwort!",
"Please input the correct ID card number!": "Bitte geben Sie die korrekte Ausweisnummer ein!",
"Please input your Email!": "Bitte geben Sie Ihre E-Mail-Adresse ein!",
"Please input your ID card number!": "Bitte geben Sie Ihre Personalausweisnummer ein!",
@ -637,17 +637,17 @@
"Database - Tooltip": "Der ursprüngliche Datenbankname",
"Database type": "Datenbanktyp",
"Database type - Tooltip": "Datenbanktyp, der alle Datenbanken unterstützt, die von XORM unterstützt werden, wie MySQL, PostgreSQL, SQL Server, Oracle, SQLite, usw.",
"Edit Syncer": "Edit Syncer",
"Edit Syncer": "Syncer bearbeiten",
"Error text": "Fehlermeldung",
"Error text - Tooltip": "Fehler Text",
"Is hashed": "wurde gehasht",
"Is hashed": "ist gehasht",
"New Syncer": "Neuer Syncer",
"Sync interval": "Synchronisierungsintervall",
"Sync interval - Tooltip": "Einheit in Sekunden",
"Table": "Tabelle",
"Table - Tooltip": "Name der Datenbanktabelle",
"Table columns": "Tabellenspalten",
"Table columns - Tooltip": "zu Deutsch: Spalten in der Tabelle, die an der Datensynchronisierung beteiligt sind. Spalten, die nicht an der Synchronisierung beteiligt sind, müssen nicht hinzugefügt werden",
"Table columns - Tooltip": "Spalten in der Tabelle, die an der Datensynchronisierung beteiligt sind. Spalten, die nicht an der Synchronisierung beteiligt sind, müssen nicht hinzugefügt werden",
"Table primary key": "Primärschlüssel der Tabelle",
"Table primary key - Tooltip": "Primärschlüssel in einer Tabelle, wie beispielsweise eine ID"
},
@ -655,7 +655,7 @@
"About Casdoor": "Über Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "Eine Identitäts- und Zugriffsverwaltung (IAM) / Single-Sign-On (SSO) Plattform mit Web-UI, die OAuth 2.0, OIDC, SAML und CAS unterstützt",
"CPU Usage": "CPU-Auslastung",
"Community": "Gemeinschaft",
"Community": "Community",
"Failed to get CPU usage": "Konnte CPU-Auslastung nicht abrufen",
"Failed to get memory usage": "Fehler beim Abrufen der Speichernutzung",
"Memory Usage": "Speichernutzung",
@ -664,29 +664,29 @@
"Version": "Version"
},
"theme": {
"Blossom": "Blüte",
"Border radius": "Eckradius",
"Compact": "Kompakt",
"Customize theme": "Anpassen des Themas",
"Dark": "Dunkelheit",
"Default": "Voreinstellung",
"Blossom": "Blossom",
"Border radius": "Border Radius",
"Compact": "Compact",
"Customize theme": "Anpassen des Themes",
"Dark": "Dunkel",
"Default": "Standardeinstellungen",
"Document": "Dokument",
"Is compact": "Ist kompakt",
"Primary color": "Primärfarbe",
"Theme": "Thema",
"Theme - Tooltip": "Stilthema der Anwendung"
"Theme": "Theme",
"Theme - Tooltip": "Stiltheme der Anwendung"
},
"token": {
"Access token": "Zugriffstoken",
"Access token": "Access-Token",
"Authorization code": "Authorisierungscode",
"Edit Token": "Edit-Token bearbeiten",
"Edit Token": "Token bearbeiten",
"Expires in": "läuft ab in",
"New Token": "Neues Token",
"New Token": "Neuer Token",
"Token type": "Token-Typ"
},
"user": {
"3rd-party logins": "3rd-Party-Logins",
"3rd-party logins - Tooltip": "Soziale Anmeldungen, die vom Benutzer verknüpft werden",
"3rd-party logins": "Drittanbieter-Logins",
"3rd-party logins - Tooltip": "Drittanbieter-Anmeldungen, die mit dem Benutzer verknüpft sind",
"Address": "Adresse",
"Address - Tooltip": "Wohnadresse",
"Affiliation": "Zugehörigkeit",
@ -700,22 +700,22 @@
"Country/Region - Tooltip": "Land oder Region",
"Edit User": "Benutzer bearbeiten",
"Email cannot be empty": "E-Mail darf nicht leer sein",
"Email/phone reset successfully": "E-Mail-/Telefonrücksetzung erfolgreich durchgeführt",
"Empty input!": "Leereingabe!",
"Email/phone reset successfully": "E-Mail-/Telefon-Zurücksetzung erfolgreich durchgeführt",
"Empty input!": "Leere Eingabe!",
"Homepage": "Startseite des Benutzers",
"Homepage - Tooltip": "Homepage-URL des Benutzers",
"ID card": "Ausweis",
"Input your email": "Gib deine E-Mail-Adresse ein",
"Input your email": "Geben Sie Ihre E-Mail-Adresse ein",
"Input your phone number": "Geben Sie Ihre Telefonnummer ein",
"Is admin": "Ist Admin",
"Is admin - Tooltip": "Ist ein Administrator der Organisation, zu der der Benutzer gehört",
"Is deleted": "wurde gelöscht",
"Is deleted": "ist gelöscht",
"Is deleted - Tooltip": "\"Gelöschte Benutzer behalten nur Datenbankdatensätze und können keine Operationen ausführen.\"",
"Is forbidden": "Ist verboten",
"Is forbidden - Tooltip": "Verbotene Benutzer können sich nicht mehr einloggen",
"Is global admin": "Ist weltweiter Administrator",
"Is global admin": "Ist globaler Administrator",
"Is global admin - Tooltip": "Ist ein Administrator von Casdoor",
"Keys": "Schlüssel",
"Keys": "Keys",
"Link": "Link",
"Location": "Ort",
"Location - Tooltip": "Stadt des Wohnsitzes",
@ -724,22 +724,22 @@
"New Email": "Neue E-Mail",
"New Password": "Neues Passwort",
"New User": "Neuer Benutzer",
"New phone": "Neues Telefon",
"New phone": "Neue Telefonnummer",
"Old Password": "Altes Passwort",
"Password set successfully": "Passwort erfolgreich festgelegt",
"Phone cannot be empty": "Telefon kann nicht leer sein",
"Phone cannot be empty": "Telefonnummer kann nicht leer sein",
"Please select avatar from resources": "Bitte wählen Sie einen Avatar aus den Ressourcen aus",
"Properties": "Eigenschaften",
"Properties - Tooltip": "Eigenschaften des Benutzers",
"Re-enter New": "Neueingabe betreten",
"Reset Email...": "Reset E-Mail...",
"Re-enter New": "Neueingabe wiederholen",
"Reset Email...": "E-Mail zurücksetzen...",
"Reset Phone...": "Telefon zurücksetzen...",
"Select a photo...": "Wählen Sie ein Foto aus...",
"Set Password": "Passwort festlegen",
"Set new profile picture": "Neues Profilbild festlegen",
"Set password...": "Passwort festlegen...",
"Tag": "Tag",
"Tag - Tooltip": "Tag des Benutzers",
"Tag - Tooltip": "Tags des Benutzers",
"Title": "Titel",
"Title - Tooltip": "Position in der Zugehörigkeit",
"Two passwords you typed do not match.": "Zwei von Ihnen eingegebene Passwörter stimmen nicht überein.",
@ -749,10 +749,10 @@
"Values": "Werte",
"Verification code sent": "Bestätigungscode gesendet",
"WebAuthn credentials": "WebAuthn-Anmeldeinformationen",
"input password": "Eingabe des Passworts"
"input password": "Passwort eingeben"
},
"webhook": {
"Content type": "Inhaltstyp",
"Content type": "Content-Type",
"Content type - Tooltip": "Inhaltstyp",
"Edit Webhook": "Webhook bearbeiten",
"Events": "Ereignisse",
@ -760,9 +760,9 @@
"Headers": "Überschriften",
"Headers - Tooltip": "HTTP-Header (Schlüssel-Wert-Paare)",
"Is user extended": "Wurde der Benutzer erweitert?",
"Is user extended - Tooltip": "Sollten die erweiterten Felder des Benutzers in das JSON eingeschlossen werden?",
"Is user extended - Tooltip": "Sollten die erweiterten Felder des Benutzers in das JSON inkludiert werden?",
"Method - Tooltip": "HTTP Methode",
"New Webhook": "Neuer Webhook",
"New Webhook": "Neue Webhook",
"Value": "Wert"
}
}

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
"Follow organization theme": "Follow organization theme",
"Form CSS": "Form CSS",
"Form CSS - Edit": "Form CSS - Edit",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Incremental": "Incremental",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"New Application": "New Application",
"No verification": "No verification",
"None": "None",
"Normal": "Normal",
"Only signup": "Only signup",
"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",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Redirect URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "Redirect URL (Assertion Consumer Service POST Binding URL)",
"Redirect URLs": "Redirect URLs",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Side panel HTML - Edit",
"Side panel HTML - Tooltip": "Customize the HTML code for the side panel of the login page",
"Sign Up Error": "Sign Up Error",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"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",
@ -504,6 +513,8 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "SAML metadata",
"Method - Tooltip": "Login method, QR code or silent login",
"New Provider": "New Provider",
"Normal": "Normal",
"Parse": "Parse",
"Parse metadata successfully": "Parse metadata successfully",
"Path prefix": "Path prefix",
@ -555,8 +567,10 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Template code": "Template code",
@ -564,6 +578,7 @@
"Test Email": "Test Email",
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -621,6 +636,7 @@
"The input is not valid Email!": "The input is not valid Email!",
"The input is not valid Phone!": "The input is not valid Phone!",
"Username": "Username",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "Your account has been created!",
"Your confirmed password is inconsistent with the password!": "Your confirmed password is inconsistent with the password!",
"sign in now": "sign in now"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Ya sea permitir que los usuarios registren una nueva cuenta",
"Failed to sign in": "Error al iniciar sesión",
"File uploaded successfully": "Archivo subido exitosamente",
"First, last": "First, last",
"Follow organization theme": "Seguir el tema de la organización",
"Form CSS": "Formulario CSS",
"Form CSS - Edit": "Formulario CSS - Editar",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Ubicación de los formularios de registro, inicio de sesión y olvido de contraseña",
"Grant types": "Tipos de subvenciones",
"Grant types - Tooltip": "Selecciona cuáles tipos de subvenciones están permitidas en el protocolo OAuth",
"Incremental": "Incremental",
"Left": "Izquierda",
"Logged in successfully": "Acceso satisfactorio",
"Logged out successfully": "Cerró sesión exitosamente",
"New Application": "Nueva aplicación",
"No verification": "No verification",
"None": "Ninguno",
"Normal": "Normal",
"Only signup": "Only signup",
"Please input your application!": "¡Por favor, ingrese su solicitud!",
"Please input your organization!": "¡Por favor, ingrese su organización!",
"Please select a HTML file": "Por favor, seleccione un archivo HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL de la página de acceso exitosamente copiada al portapapeles, por favor péguela en la ventana de incógnito o en otro navegador",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Redireccionar URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "URL de redireccionamiento (URL de enlace de publicación del servicio consumidor de afirmaciones)",
"Redirect URLs": "Redireccionar URLs",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Panel lateral HTML - Editar",
"Side panel HTML - Tooltip": "Personaliza el código HTML del panel lateral de la página de inicio de sesión",
"Sign Up Error": "Error de registro",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "La URL de la página de inicio de sesión fue copiada al portapapeles exitosamente, por favor péguela en una ventana de incógnito o en otro navegador",
"Signin session": "Sesión de inicio de sesión",
"Signup items": "Artículos de registro",
@ -504,6 +513,8 @@
"Host - Tooltip": "Nombre del anfitrión",
"IdP": "IdP = Proveedor de Identidad",
"IdP certificate": "Certificado de proveedor de identidad (IdP)",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL del emisor",
"Issuer URL - Tooltip": "URL del emisor",
"Link copied to clipboard successfully": "Enlace copiado al portapapeles satisfactoriamente",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "Metadatos SAML",
"Method - Tooltip": "Método de inicio de sesión, código QR o inicio de sesión silencioso",
"New Provider": "Nuevo proveedor",
"Normal": "Normal",
"Parse": "Analizar",
"Parse metadata successfully": "Analizar los metadatos con éxito",
"Path prefix": "Prefijo de ruta",
@ -555,8 +567,10 @@
"Signup HTML": "Registro HTML",
"Signup HTML - Edit": "Registro HTML - Editar",
"Signup HTML - Tooltip": "HTML personalizado para reemplazar el estilo predeterminado de la página de registro",
"Silent": "Silent",
"Site key": "Clave del sitio",
"Site key - Tooltip": "Clave del sitio",
"Sliding Validation": "Sliding Validation",
"Sub type": "Subtipo",
"Sub type - Tooltip": "Subtipo",
"Template code": "Código de plantilla",
@ -564,6 +578,7 @@
"Test Email": "Correo de prueba",
"Test Email - Tooltip": "Dirección de correo electrónico para recibir mensajes de prueba",
"Test SMTP Connection": "Prueba de conexión SMTP",
"Third-party": "Third-party",
"Token URL": "Token URL",
"Token URL - Tooltip": "URL de token",
"Type": "Tipo",
@ -621,6 +636,7 @@
"The input is not valid Email!": "¡La entrada no es un correo electrónico válido!",
"The input is not valid Phone!": "¡La entrada no es un número de teléfono válido!",
"Username": "Nombre de usuario",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "¡Su cuenta ha sido creada!",
"Your confirmed password is inconsistent with the password!": "¡Su contraseña confirmada no es coherente con la contraseña!",
"sign in now": "Inicie sesión ahora"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Doit-on autoriser les utilisateurs à créer un nouveau compte ?",
"Failed to sign in": "Échec de la connexion",
"File uploaded successfully": "Fichier téléchargé avec succès",
"First, last": "First, last",
"Follow organization theme": "Suivre le thème de l'organisation",
"Form CSS": "Formulaire CSS",
"Form CSS - Edit": "Form CSS - Modifier",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Emplacement des formulaires d'inscription, de connexion et de récupération de mot de passe",
"Grant types": "Types de subventions",
"Grant types - Tooltip": "Sélectionnez les types d'autorisations autorisés dans le protocole OAuth",
"Incremental": "Incremental",
"Left": "gauche",
"Logged in successfully": "Connecté avec succès",
"Logged out successfully": "Déconnecté avec succès",
"New Application": "Nouvelle application",
"No verification": "No verification",
"None": "Aucun",
"Normal": "Normal",
"Only signup": "Only signup",
"Please input your application!": "Veuillez saisir votre demande d'application !",
"Please input your organization!": "S'il vous plaît saisir votre organisation !",
"Please select a HTML file": "S'il vous plaît sélectionnez un fichier HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL de la page rapide copiée avec succès dans le presse-papiers, veuillez la coller dans la fenêtre de navigation privée ou dans un autre navigateur",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Rediriger l'URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "URL de redirection (URL de liaison POST du service consommateur d'assertions)",
"Redirect URLs": "Rediriger les URL",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Panneau latéral HTML - Modifier",
"Side panel HTML - Tooltip": "Personnalisez le code HTML du panneau latéral de la page de connexion",
"Sign Up Error": "Erreur d'inscription",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "L'URL de la page de connexion a été copiée avec succès dans le presse-papiers, veuillez la coller dans la fenêtre de navigation privée ou dans un autre navigateur",
"Signin session": "Session de connexion",
"Signup items": "Les éléments d'inscription",
@ -504,6 +513,8 @@
"Host - Tooltip": "Nom d'hôte",
"IdP": "IdP",
"IdP certificate": "Certificat IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL de l'émetteur",
"Issuer URL - Tooltip": "URL de l'émetteur",
"Link copied to clipboard successfully": "Lien copié avec succès dans le presse-papiers",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "Métadonnées SAML",
"Method - Tooltip": "Méthode de connexion, code QR ou connexion silencieuse",
"New Provider": "Nouveau fournisseur",
"Normal": "Normal",
"Parse": "Parser",
"Parse metadata successfully": "Parcourir les métadonnées avec succès",
"Path prefix": "Préfixe de chemin",
@ -555,8 +567,10 @@
"Signup HTML": "Inscription HTML",
"Signup HTML - Edit": "Inscription HTML - éditer",
"Signup HTML - Tooltip": "HTML personnalisé pour remplacer le style par défaut de la page d'inscription",
"Silent": "Silent",
"Site key": "Clé de site",
"Site key - Tooltip": "Clé de site",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sous-type",
"Sub type - Tooltip": "Sous-type",
"Template code": "Code modèle",
@ -564,6 +578,7 @@
"Test Email": "Courriel de test",
"Test Email - Tooltip": "Adresse e-mail pour recevoir des courriels de test",
"Test SMTP Connection": "Test de connexion SMTP",
"Third-party": "Third-party",
"Token URL": "URL de jeton",
"Token URL - Tooltip": "URL de jeton",
"Type": "Type",
@ -621,6 +636,7 @@
"The input is not valid Email!": "L'entrée n'est pas un e-mail valide !",
"The input is not valid Phone!": "L'entrée n'est pas un numéro de téléphone valide !",
"Username": "Nom d'utilisateur",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "Votre compte a été créé !",
"Your confirmed password is inconsistent with the password!": "Votre mot de passe confirmé est incompatible avec le mot de passe !",
"sign in now": "Connectez-vous maintenant"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Apakah akan mengizinkan pengguna untuk mendaftar akun baru",
"Failed to sign in": "Gagal masuk",
"File uploaded successfully": "Berkas telah diunggah dengan sukses",
"First, last": "First, last",
"Follow organization theme": "Ikuti tema organisasi",
"Form CSS": "Formulir CSS",
"Form CSS - Edit": "Formulir CSS - Edit",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Tempat pendaftaran, masuk, dan lupa kata sandi",
"Grant types": "Jenis-jenis hibah",
"Grant types - Tooltip": "Pilih jenis hibah apa yang diperbolehkan dalam protokol OAuth",
"Incremental": "Incremental",
"Left": "Kiri",
"Logged in successfully": "Berhasil masuk",
"Logged out successfully": "Berhasil keluar dari sistem",
"New Application": "Aplikasi Baru",
"No verification": "No verification",
"None": "Tidak ada",
"Normal": "Normal",
"Only signup": "Only signup",
"Please input your application!": "Silakan masukkan aplikasi Anda!",
"Please input your organization!": "Silakan masukkan organisasi Anda!",
"Please select a HTML file": "Silahkan pilih file HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Tautan halaman Prompt berhasil disalin ke papan klip, silakan tempelkan ke jendela penyamaran atau browser lainnya",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Mengalihkan URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "URL pengalihan (Penyanggah Konsumen Layanan Ikatan POST URL)",
"Redirect URLs": "Mengarahkan URL",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Panel sisi HTML - Sunting",
"Side panel HTML - Tooltip": "Menyesuaikan kode HTML untuk panel samping halaman login",
"Sign Up Error": "Kesalahan Pendaftaran",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL halaman masuk berhasil disalin ke clipboard, silakan tempelkan di jendela penyamaran atau browser lainnya",
"Signin session": "Sesi masuk",
"Signup items": "Item pendaftaran",
@ -504,6 +513,8 @@
"Host - Tooltip": "Nama tuan rumah",
"IdP": "IdP",
"IdP certificate": "Sertifikat IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL penerbit",
"Issuer URL - Tooltip": "URL Penerbit",
"Link copied to clipboard successfully": "Tautan berhasil disalin ke papan klip",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "Metadata SAML",
"Method - Tooltip": "Metode login, kode QR atau login tanpa suara",
"New Provider": "Penyedia Baru",
"Normal": "Normal",
"Parse": "Parse: Memecah atau mengurai data atau teks menjadi bagian-bagian yang lebih kecil dan lebih mudah dipahami atau dimanipulasi",
"Parse metadata successfully": "Berhasil mem-parse metadata",
"Path prefix": "Awalan jalur",
@ -555,8 +567,10 @@
"Signup HTML": "Pendaftaran HTML",
"Signup HTML - Edit": "Pendaftaran HTML - Sunting",
"Signup HTML - Tooltip": "HTML khusus untuk mengganti gaya halaman pendaftaran bawaan",
"Silent": "Silent",
"Site key": "Kunci situs",
"Site key - Tooltip": "Kunci situs atau kunci halaman web",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub jenis",
"Sub type - Tooltip": "Sub jenis",
"Template code": "Kode template",
@ -564,6 +578,7 @@
"Test Email": "Email Uji Coba",
"Test Email - Tooltip": "Alamat email untuk menerima email percobaan",
"Test SMTP Connection": "Tes Koneksi SMTP",
"Third-party": "Third-party",
"Token URL": "Token URL: Tautan Token",
"Token URL - Tooltip": "Token URL: URL Token",
"Type": "Jenis",
@ -621,6 +636,7 @@
"The input is not valid Email!": "Input yang dimasukkan bukan sesuai dengan format Email yang valid!",
"The input is not valid Phone!": "Masukan ponsel tidak valid!",
"Username": "Nama pengguna",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "Akun Anda telah dibuat!",
"Your confirmed password is inconsistent with the password!": "Kata sandi yang dikonfirmasi tidak konsisten dengan kata sandi!",
"sign in now": "Masuk sekarang"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "新しいアカウントの登録をユーザーに許可するかどうか",
"Failed to sign in": "ログインに失敗しました",
"File uploaded successfully": "ファイルが正常にアップロードされました",
"First, last": "First, last",
"Follow organization theme": "組織のテーマに従ってください",
"Form CSS": "フォームCSS",
"Form CSS - Edit": "フォームのCSS - 編集",
@ -49,15 +50,21 @@
"Form position - Tooltip": "登録、ログイン、パスワード忘れフォームの位置",
"Grant types": "グラント種類",
"Grant types - Tooltip": "OAuthプロトコルで許可されているグラントタイプを選択してください",
"Incremental": "Incremental",
"Left": "左",
"Logged in successfully": "正常にログインしました",
"Logged out successfully": "正常にログアウトしました",
"New Application": "新しいアプリケーション",
"No verification": "No verification",
"None": "なし",
"Normal": "Normal",
"Only signup": "Only signup",
"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が正常にクリップボードにコピーされました。インコグニートウィンドウまたは別のブラウザに貼り付けてください",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "リダイレクトURL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "リダイレクトURLアサーションコンシューマサービスPOSTバインディングURL",
"Redirect URLs": "リダイレクトURL",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "サイドパネルのHTML - 編集",
"Side panel HTML - Tooltip": "ログインページのサイドパネルに対するHTMLコードをカスタマイズしてください",
"Sign Up Error": "サインアップエラー",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "サインインページのURLがクリップボードに正常にコピーされました。インコグニートウィンドウまたは別のブラウザに貼り付けてください",
"Signin session": "サインインセッション",
"Signup items": "サインアップアイテム",
@ -504,6 +513,8 @@
"Host - Tooltip": "ホストの名前",
"IdP": "IdP",
"IdP certificate": "IdP証明書",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "発行者のURL",
"Issuer URL - Tooltip": "発行者URL",
"Link copied to clipboard successfully": "リンクがクリップボードに正常にコピーされました",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "SAMLのメタデータ",
"Method - Tooltip": "ログイン方法、QRコードまたはサイレントログイン",
"New Provider": "新しい提供者",
"Normal": "Normal",
"Parse": "パースする",
"Parse metadata successfully": "メタデータを正常に解析しました",
"Path prefix": "パスプレフィックス",
@ -555,8 +567,10 @@
"Signup HTML": "サインアップ HTML",
"Signup HTML - Edit": "サインアップ HTML - 編集",
"Signup HTML - Tooltip": "デフォルトのサインアップページスタイルを置き換えるためのカスタムHTML",
"Silent": "Silent",
"Site key": "サイトキー",
"Site key - Tooltip": "サイトキー",
"Sliding Validation": "Sliding Validation",
"Sub type": "サブタイプ",
"Sub type - Tooltip": "サブタイプ",
"Template code": "テンプレートコード",
@ -564,6 +578,7 @@
"Test Email": "テストメール",
"Test Email - Tooltip": "テストメールを受け取るためのメールアドレス",
"Test SMTP Connection": "SMTP接続をテストする",
"Third-party": "Third-party",
"Token URL": "トークンのURL",
"Token URL - Tooltip": "トークンURL",
"Type": "タイプ",
@ -621,6 +636,7 @@
"The input is not valid Email!": "入力されたものは有効なメールではありません",
"The input is not valid Phone!": "この入力は有効な電話番号ではありません!",
"Username": "ユーザー名",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "あなたのアカウントが作成されました!",
"Your confirmed password is inconsistent with the password!": "確認されたパスワードは、パスワードと矛盾しています!",
"sign in now": "今すぐサインインしてください"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "사용자가 새로운 계정을 등록할지 여부",
"Failed to sign in": "로그인 실패했습니다",
"File uploaded successfully": "파일이 성공적으로 업로드되었습니다",
"First, last": "First, last",
"Follow organization theme": "조직의 주제를 따르세요",
"Form CSS": "CSS 양식",
"Form CSS - Edit": "폼 CSS - 편집",
@ -49,15 +50,21 @@
"Form position - Tooltip": "가입, 로그인 및 비밀번호 재설정 양식의 위치",
"Grant types": "Grant types: 부여 유형",
"Grant types - Tooltip": "OAuth 프로토콜에서 허용되는 그란트 유형을 선택하십시오",
"Incremental": "Incremental",
"Left": "왼쪽",
"Logged in successfully": "성공적으로 로그인했습니다",
"Logged out successfully": "로그아웃이 성공적으로 되었습니다",
"New Application": "새로운 응용 프로그램",
"No verification": "No verification",
"None": "없음",
"Normal": "Normal",
"Only signup": "Only signup",
"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이 클립 보드에 성공적으로 복사되었습니다. 시크릿 모드 창이나 다른 브라우저에 붙여 넣으세요",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "리디렉트 URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "리디렉션 URL (단언 서비스 소비자 POST 바인딩 URL)",
"Redirect URLs": "URL 리디렉트",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "사이드 패널 HTML - 편집",
"Side panel HTML - Tooltip": "로그인 페이지의 측면 패널용 HTML 코드를 맞춤 설정하십시오",
"Sign Up Error": "가입 오류",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "로그인 페이지 URL이 클립보드에 성공적으로 복사되었습니다. 익명 창이나 다른 브라우저에 붙여넣어주세요",
"Signin session": "로그인 세션",
"Signup items": "가입 항목",
@ -504,6 +513,8 @@
"Host - Tooltip": "호스트의 이름",
"IdP": "IdP",
"IdP certificate": "IdP 인증서",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "발행자 URL",
"Issuer URL - Tooltip": "발급자 URL",
"Link copied to clipboard successfully": "링크가 클립보드에 성공적으로 복사되었습니다",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "SAML 메타데이터",
"Method - Tooltip": "로그인 방법, QR 코드 또는 음성 로그인",
"New Provider": "새로운 공급 업체",
"Normal": "Normal",
"Parse": "파싱",
"Parse metadata successfully": "메타데이터를 성공적으로 분석했습니다",
"Path prefix": "경로 접두어",
@ -555,8 +567,10 @@
"Signup HTML": "가입 양식 HTML",
"Signup HTML - Edit": "가입 HTML - 수정",
"Signup HTML - Tooltip": "기본 가입 페이지 스타일을 바꾸기 위한 사용자 지정 HTML",
"Silent": "Silent",
"Site key": "사이트 키",
"Site key - Tooltip": "사이트 키",
"Sliding Validation": "Sliding Validation",
"Sub type": "하위 유형",
"Sub type - Tooltip": "서브 타입",
"Template code": "템플릿 코드",
@ -564,6 +578,7 @@
"Test Email": "테스트 이메일",
"Test Email - Tooltip": "테스트 메일을 받을 이메일 주소",
"Test SMTP Connection": "테스트 SMTP 연결",
"Third-party": "Third-party",
"Token URL": "토큰 URL",
"Token URL - Tooltip": "토큰 URL",
"Type": "타입",
@ -621,6 +636,7 @@
"The input is not valid Email!": "입력 값은 유효한 이메일이 아닙니다!",
"The input is not valid Phone!": "입력이 유효한 전화번호가 아닙니다!",
"Username": "사용자 이름",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "계정이 생성되었습니다!",
"Your confirmed password is inconsistent with the password!": "확인된 비밀번호가 비밀번호와 일치하지 않습니다!",
"sign in now": "지금 로그인하십시오"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Разрешить ли пользователям зарегистрировать новый аккаунт",
"Failed to sign in": "Не удалось войти в систему",
"File uploaded successfully": "Файл успешно загружен",
"First, last": "First, last",
"Follow organization theme": "Cледуйте теме организации",
"Form CSS": "Форма CSS",
"Form CSS - Edit": "Форма CSS - Редактирование",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Местоположение форм регистрации, входа и восстановления пароля",
"Grant types": "Типы грантов",
"Grant types - Tooltip": "Выберите, какие типы грантов разрешены в протоколе OAuth",
"Incremental": "Incremental",
"Left": "Левый",
"Logged in successfully": "Успешный вход в систему",
"Logged out successfully": "Успешный выход из системы",
"New Application": "Новое приложение",
"No verification": "No verification",
"None": "Никакой",
"Normal": "Normal",
"Only signup": "Only signup",
"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 страницы успешно скопирован в буфер обмена, пожалуйста, вставьте его в режиме инкогнито или в другом браузере",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Перенаправление URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "Перенаправление URL (адрес сервиса потребителя утверждения POST-связывание)",
"Redirect URLs": "Перенаправление URL-адресов",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Боковая панель HTML - Редактировать",
"Side panel HTML - Tooltip": "Настроить HTML-код для боковой панели страницы входа в систему",
"Sign Up Error": "Ошибка при регистрации",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL страницы входа скопирован успешно, пожалуйста, вставьте ее в инкогнито-окно или другой браузер",
"Signin session": "Сессия входа в систему",
"Signup items": "Элементы регистрации",
@ -504,6 +513,8 @@
"Host - Tooltip": "Имя хоста",
"IdP": "IdP",
"IdP certificate": "Сертификат IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL выпускающего органа",
"Issuer URL - Tooltip": "URL эмитента",
"Link copied to clipboard successfully": "Ссылка успешно скопирована в буфер обмена",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "Метаданные SAML",
"Method - Tooltip": "Метод входа, QR-код или беззвучный вход",
"New Provider": "Новый провайдер",
"Normal": "Normal",
"Parse": "Спарсить",
"Parse metadata successfully": "Успешно обработана метаданные",
"Path prefix": "Префикс пути",
@ -555,8 +567,10 @@
"Signup HTML": "Регистрационная форма HTML",
"Signup HTML - Edit": "Регистрационная форма HTML - Редактировать",
"Signup HTML - Tooltip": "Пользовательский HTML для замены стиля стандартной страницы регистрации",
"Silent": "Silent",
"Site key": "Ключ сайта",
"Site key - Tooltip": "Ключ сайта",
"Sliding Validation": "Sliding Validation",
"Sub type": "Подтип",
"Sub type - Tooltip": "Подтип",
"Template code": "Шаблонный код",
@ -564,6 +578,7 @@
"Test Email": "Тестовое письмо",
"Test Email - Tooltip": "Адрес электронной почты для получения тестовых писем",
"Test SMTP Connection": "Тестирование соединения SMTP",
"Third-party": "Third-party",
"Token URL": "Токен URL (URL-адрес маркера)",
"Token URL - Tooltip": "Токен URL",
"Type": "Тип",
@ -621,6 +636,7 @@
"The input is not valid Email!": "Ввод не является действительным адресом электронной почты!",
"The input is not valid Phone!": "Ввод не является действительным телефоном!",
"Username": "Имя пользователя",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "Ваш аккаунт был создан!",
"Your confirmed password is inconsistent with the password!": "Ваш подтвержденный пароль не соответствует паролю!",
"sign in now": "войти сейчас"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "Có cho phép người dùng đăng ký tài khoản mới không?",
"Failed to sign in": "Không đăng nhập được",
"File uploaded successfully": "Tệp được tải lên thành công",
"First, last": "First, last",
"Follow organization theme": "Theo chủ đề tổ chức",
"Form CSS": "Mẫu CSS",
"Form CSS - Edit": "Biểu mẫu CSS - Chỉnh sửa",
@ -49,15 +50,21 @@
"Form position - Tooltip": "Vị trí của các biểu mẫu đăng ký, đăng nhập và quên mật khẩu",
"Grant types": "Loại hỗ trợ",
"Grant types - Tooltip": "Chọn loại hỗ trợ được cho phép trong giao thức OAuth",
"Incremental": "Incremental",
"Left": "Trái",
"Logged in successfully": "Đăng nhập thành công",
"Logged out successfully": "Đã đăng xuất thành công",
"New Application": "Ứng dụng mới",
"No verification": "No verification",
"None": "Không có gì",
"Normal": "Normal",
"Only signup": "Only signup",
"Please input your application!": "Vui lòng nhập đơn của bạn!",
"Please input your organization!": "Vui lòng nhập tên tổ chức của bạn!",
"Please select a HTML file": "Vui lòng chọn tệp HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Đã sao chép đường dẫn trang một cách thành công, hãy dán nó vào cửa sổ ẩn danh hoặc trình duyệt khác",
"Random": "Random",
"Real name": "Real name",
"Redirect URL": "Chuyển hướng đường dẫn URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "Điều hướng URL (URL khung POST Dịch vụ Tiêu thụ Khẳng định)",
"Redirect URLs": "Chuyển hướng URL",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "Bảng Panel Bên - Chỉnh sửa HTML",
"Side panel HTML - Tooltip": "Tùy chỉnh mã HTML cho bảng điều khiển bên của trang đăng nhập",
"Sign Up Error": "Lỗi đăng ký",
"Signin": "Signin",
"Signin (Default True)": "Signin (Default True)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Đã sao chép thành công địa chỉ URL trang Đăng nhập vào clipboard, vui lòng dán nó vào cửa sổ ẩn danh hoặc trình duyệt khác",
"Signin session": "Phiên đăng nhập",
"Signup items": "Các mục đăng ký",
@ -504,6 +513,8 @@
"Host - Tooltip": "Tên của người chủ chỗ ở",
"IdP": "IdP",
"IdP certificate": "Chứng chỉ IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Địa chỉ URL của người phát hành",
"Issuer URL - Tooltip": "Địa chỉ URL của nhà phát hành",
"Link copied to clipboard successfully": "Đã sao chép liên kết vào bộ nhớ tạm thành công",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "SAML metadata: siêu dữ liệu SAML",
"Method - Tooltip": "Phương thức đăng nhập, mã QR hoặc đăng nhập im lặng",
"New Provider": "Nhà cung cấp mới",
"Normal": "Normal",
"Parse": "Phân tích cú pháp",
"Parse metadata successfully": "Phân tích siêu dữ liệu thành công",
"Path prefix": "Tiền tố đường dẫn",
@ -555,8 +567,10 @@
"Signup HTML": "Đăng ký HTML",
"Signup HTML - Edit": "Đăng ký HTML - Chỉnh sửa",
"Signup HTML - Tooltip": "Trang HTML tùy chỉnh để thay thế phong cách trang đăng ký mặc định",
"Silent": "Silent",
"Site key": "Khóa trang web",
"Site key - Tooltip": "Khóa trang web",
"Sliding Validation": "Sliding Validation",
"Sub type": "Loại phụ",
"Sub type - Tooltip": "Loại phụ",
"Template code": "Mã mẫu của template",
@ -564,6 +578,7 @@
"Test Email": "Thư Email kiểm tra",
"Test Email - Tooltip": "Địa chỉ email để nhận thư kiểm tra",
"Test SMTP Connection": "Kiểm tra kết nối SMTP",
"Third-party": "Third-party",
"Token URL": "Đường dẫn Token",
"Token URL - Tooltip": "Địa chỉ URL của Token",
"Type": "Kiểu",
@ -621,6 +636,7 @@
"The input is not valid Email!": "Đầu vào không phải là địa chỉ Email hợp lệ!",
"The input is not valid Phone!": "Đầu vào không hợp lệ! Số điện thoại không hợp lệ!",
"Username": "Tên đăng nhập",
"Username - Tooltip": "Username - Tooltip",
"Your account has been created!": "Tài khoản của bạn đã được tạo!",
"Your confirmed password is inconsistent with the password!": "Mật khẩu xác nhận của bạn không khớp với mật khẩu đã nhập!",
"sign in now": "Đăng nhập ngay bây giờ"

View File

@ -41,6 +41,7 @@
"Enable signup - Tooltip": "是否允许用户注册",
"Failed to sign in": "登录失败",
"File uploaded successfully": "文件上传成功",
"First, last": "名字, 姓氏",
"Follow organization theme": "使用组织主题",
"Form CSS": "表单CSS",
"Form CSS - Edit": "编辑表单CSS",
@ -49,15 +50,21 @@
"Form position - Tooltip": "注册、登录、忘记密码等表单的位置",
"Grant types": "OAuth授权类型",
"Grant types - Tooltip": "选择允许哪些OAuth协议中的grant types",
"Incremental": "递增",
"Left": "居左",
"Logged in successfully": "登录成功",
"Logged out successfully": "登出成功",
"New Application": "添加应用",
"No verification": "不校验",
"None": "关闭",
"Normal": "标准",
"Only signup": "仅注册",
"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已成功复制到剪贴板请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
"Random": "随机",
"Real name": "真实姓名",
"Redirect URL": "重定向 URL",
"Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip": "回复 URL (断言使用者服务 URL, 使用POST请求返回响应) - Tooltip",
"Redirect URLs": "重定向 URLs",
@ -74,6 +81,8 @@
"Side panel HTML - Edit": "侧面板HTML - 编辑",
"Side panel HTML - Tooltip": "自定义登录页面侧面板的HTML代码",
"Sign Up Error": "注册错误",
"Signin": "登录",
"Signin (Default True)": "登录 (默认同意)",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "登录页面URL已成功复制到剪贴板请粘贴到当前浏览器的隐身模式窗口或另一个浏览器访问",
"Signin session": "保持登录会话",
"Signup items": "注册项",
@ -504,6 +513,8 @@
"Host - Tooltip": "主机名",
"IdP": "IdP",
"IdP certificate": "IdP公钥证书",
"Intelligent Validation": "智能验证",
"Internal": "内部",
"Issuer URL": "Issuer链接",
"Issuer URL - Tooltip": "Issuer链接URL",
"Link copied to clipboard successfully": "链接已成功复制到剪贴板",
@ -511,6 +522,7 @@
"Metadata - Tooltip": "SAML元数据",
"Method - Tooltip": "登录方法,二维码或者静默授权登录",
"New Provider": "添加提供商",
"Normal": "标准",
"Parse": "解析",
"Parse metadata successfully": "解析元数据成功",
"Path prefix": "路径前缀",
@ -555,8 +567,10 @@
"Signup HTML": "注册页面HTML",
"Signup HTML - Edit": "注册页面HTML - 编辑",
"Signup HTML - Tooltip": "自定义HTML用于替换默认的注册页面样式",
"Silent": "静默",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "滑块验证",
"Sub type": "子类型",
"Sub type - Tooltip": "子类型",
"Template code": "模板代码",
@ -564,6 +578,7 @@
"Test Email": "测试Email配置",
"Test Email - Tooltip": "接收测试邮件的Email邮箱",
"Test SMTP Connection": "测试SMTP连接",
"Third-party": "第三方",
"Token URL": "Token URL",
"Token URL - Tooltip": "自定义OAuth的Token URL",
"Type": "类型",
@ -621,6 +636,7 @@
"The input is not valid Email!": "您输入的电子邮箱格式有误!",
"The input is not valid Phone!": "您输入的手机号格式有误!",
"Username": "用户名",
"Username - Tooltip": "用户名",
"Your account has been created!": "您的账号已成功创建!",
"Your confirmed password is inconsistent with the password!": "您两次输入的密码不一致!",
"sign in now": "立即登录"

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
const {Option} = Select;

View File

@ -14,11 +14,11 @@
import React from "react";
import {Button, Col, Row, Table} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
import * as LdapBackend from "./backend/LdapBackend";
import * as LdapBackend from "../backend/LdapBackend";
import {Link} from "react-router-dom";
import PopconfirmModal from "./PopconfirmModal";
import PopconfirmModal from "../PopconfirmModal";
class LdapTable extends React.Component {
constructor(props) {

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Select, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
const {Option} = Select;

View File

@ -15,9 +15,9 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
import * as Provider from "./auth/Provider";
import * as Provider from "../auth/Provider";
const {Option} = Select;

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
const {Option} = Select;
@ -172,25 +172,25 @@ class SignupTable extends React.Component {
let options = [];
if (record.name === "ID") {
options = [
{id: "Random", name: "Random"},
{id: "Incremental", name: "Incremental"},
{id: "Random", name: i18next.t("application:Random")},
{id: "Incremental", name: i18next.t("application:Incremental")},
];
} else if (record.name === "Display name") {
options = [
{id: "None", name: "None"},
{id: "Real name", name: "Real name"},
{id: "First, last", name: "First, last"},
{id: "None", name: i18next.t("application:None")},
{id: "Real name", name: i18next.t("application:Real name")},
{id: "First, last", name: i18next.t("application:First, last")},
];
} else if (record.name === "Email") {
options = [
{id: "Normal", name: "Normal"},
{id: "No verification", name: "No verification"},
{id: "Normal", name: i18next.t("application:Normal")},
{id: "No verification", name: i18next.t("application:No verification")},
];
} else if (record.name === "Agreement") {
options = [
{id: "None", name: "None"},
{id: "Signin", name: "Signin"},
{id: "Signin (Default True)", name: "Signin (Default True)"},
{id: "None", name: i18next.t("application:Only signup")},
{id: "Signin", name: i18next.t("application:Signin")},
{id: "Signin (Default True)", name: i18next.t("application:Signin (Default True)")},
];
}

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
const {Option} = Select;

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, LinkOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
class UrlTable extends React.Component {

View File

@ -15,8 +15,8 @@
import React from "react";
import {Button, Table} from "antd";
import i18next from "i18next";
import * as UserWebauthnBackend from "./backend/UserWebauthnBackend";
import * as Setting from "./Setting";
import * as UserWebauthnBackend from "../backend/UserWebauthnBackend";
import * as Setting from "../Setting";
class WebAuthnCredentialTable extends React.Component {
deleteRow(table, i) {

View File

@ -15,7 +15,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
import i18next from "i18next";
class WebhookHeaderTable extends React.Component {

View File

@ -16,7 +16,7 @@ import React from "react";
import {Button, Input, Table} from "antd";
import i18next from "i18next";
import {DeleteOutlined} from "@ant-design/icons";
import * as Setting from "./Setting";
import * as Setting from "../Setting";
class PropertyTable extends React.Component {
constructor(props) {