mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-21 17:13:50 +08:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
a111fd672c | |||
9fd175eefd | |||
d9bcce9485 | |||
d183b9eca9 | |||
f24d9ae251 | |||
030c1caa50 | |||
cee2c608a2 | |||
82d0e895e0 | |||
dee9bac110 | |||
e7a6986b62 | |||
b91b4aec91 | |||
fe48c38bc6 | |||
1be777c08f | |||
8d54bfad8a | |||
728fe11a3c | |||
69e0f4e40d | |||
ba32a45693 | |||
a4d83af768 | |||
5b8f6415d9 | |||
5389cb435c | |||
9b6131890c | |||
ffc0a0e0d5 | |||
ff22bf507f | |||
2d4103d751 | |||
4611b59b08 | |||
445d3c9d0e | |||
dbebd1846f | |||
2fcc8f5bfe | |||
4b65320a96 | |||
5e8897e41b | |||
ba1646a0c3 | |||
c1cd187558 | |||
519fd655cf | |||
377ac05928 | |||
4f124ff140 | |||
d5f802ec7d |
2
.github/workflows/sync.yml
vendored
2
.github/workflows/sync.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
|
@ -20,7 +20,7 @@ COPY --from=FRONT /web/build /web/build
|
||||
CMD chmod 777 /tmp && service mariadb start&&\
|
||||
if [ "${MYSQL_ROOT_PASSWORD}" = "" ] ;then MYSQL_ROOT_PASSWORD=123456 ; fi&&\
|
||||
mysqladmin -u root password ${MYSQL_ROOT_PASSWORD} &&\
|
||||
./wait-for-it localhost:3306 -- ./server
|
||||
./wait-for-it localhost:3306 -- ./server --createDatabase=true
|
||||
|
||||
|
||||
FROM alpine:latest
|
||||
|
@ -37,6 +37,9 @@
|
||||
<a href="https://crowdin.com/project/casdoor-site">
|
||||
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
|
||||
</a>
|
||||
<a href="https://gitter.im/casbin/casdoor">
|
||||
<img alt="Gitter" src="https://badges.gitter.im/casbin/casdoor.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Online demo
|
||||
|
@ -80,6 +80,7 @@ p, *, *, GET, /api/get-app-login, *, *
|
||||
p, *, *, POST, /api/logout, *, *
|
||||
p, *, *, GET, /api/get-account, *, *
|
||||
p, *, *, POST, /api/login/oauth/access_token, *, *
|
||||
p, *, *, POST, /api/login/oauth/refresh_token, *, *
|
||||
p, *, *, GET, /api/get-application, *, *
|
||||
p, *, *, GET, /api/get-users, *, *
|
||||
p, *, *, GET, /api/get-user, *, *
|
||||
|
@ -6,6 +6,7 @@ copyrequestbody = true
|
||||
driverName = mysql
|
||||
dataSourceName = root:123456@tcp(localhost:3306)/
|
||||
dbName = casdoor
|
||||
showSql = false
|
||||
redisEndpoint =
|
||||
defaultStorageProvider =
|
||||
isCloudIntranet = false
|
||||
|
@ -38,6 +38,7 @@ type RequestForm struct {
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Affiliation string `json:"affiliation"`
|
||||
IdCard string `json:"idCard"`
|
||||
Region string `json:"region"`
|
||||
|
||||
Application string `json:"application"`
|
||||
@ -61,6 +62,7 @@ type Response struct {
|
||||
Status string `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
Sub string `json:"sub"`
|
||||
Name string `json:"name"`
|
||||
Data interface{} `json:"data"`
|
||||
Data2 interface{} `json:"data2"`
|
||||
}
|
||||
@ -151,6 +153,7 @@ func (c *ApiController) Signup() {
|
||||
Phone: form.Phone,
|
||||
Address: []string{},
|
||||
Affiliation: form.Affiliation,
|
||||
IdCard: form.IdCard,
|
||||
Region: form.Region,
|
||||
Score: getInitScore(),
|
||||
IsAdmin: false,
|
||||
@ -220,6 +223,7 @@ func (c *ApiController) GetAccount() {
|
||||
resp := Response{
|
||||
Status: "ok",
|
||||
Sub: user.Id,
|
||||
Name: user.Name,
|
||||
Data: user,
|
||||
Data2: organization,
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
// @Success 200 {array} object.Application The Response object
|
||||
// @router /get-applications [get]
|
||||
func (c *ApiController) GetApplications() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
@ -37,13 +38,22 @@ func (c *ApiController) GetApplications() {
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
organization := c.Input().Get("organization")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetApplications(owner)
|
||||
var applications []*object.Application
|
||||
if organization == "" {
|
||||
applications = object.GetApplications(owner)
|
||||
} else {
|
||||
applications = object.GetApplicationsByOrganizationName(owner, organization)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetApplicationCount(owner, field, value)))
|
||||
applications := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
applications := object.GetMaskedApplications(object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder), userId)
|
||||
c.ResponseOk(applications, paginator.Nums())
|
||||
}
|
||||
}
|
||||
@ -56,9 +66,10 @@ func (c *ApiController) GetApplications() {
|
||||
// @Success 200 {object} object.Application The Response object
|
||||
// @router /get-application [get]
|
||||
func (c *ApiController) GetApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetApplication(id)
|
||||
c.Data["json"] = object.GetMaskedApplication(object.GetApplication(id), userId)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@ -70,6 +81,7 @@ func (c *ApiController) GetApplication() {
|
||||
// @Success 200 {object} object.Application The Response object
|
||||
// @router /get-user-application [get]
|
||||
func (c *ApiController) GetUserApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
id := c.Input().Get("id")
|
||||
user := object.GetUser(id)
|
||||
if user == nil {
|
||||
@ -77,7 +89,7 @@ func (c *ApiController) GetUserApplication() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetApplicationByUser(user)
|
||||
c.Data["json"] = object.GetMaskedApplication(object.GetApplicationByUser(user), userId)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
@ -35,6 +37,21 @@ type SessionData struct {
|
||||
ExpireTime int64
|
||||
}
|
||||
|
||||
func (c *ApiController) IsGlobalAdmin() bool {
|
||||
username := c.GetSessionUsername()
|
||||
if strings.HasPrefix(username, "app/") {
|
||||
// e.g., "app/app-casnode"
|
||||
return true
|
||||
}
|
||||
|
||||
user := object.GetUser(username)
|
||||
if user == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return user.Owner == "built-in" || user.IsGlobalAdmin
|
||||
}
|
||||
|
||||
// GetSessionUsername ...
|
||||
func (c *ApiController) GetSessionUsername() string {
|
||||
// check if user session expired
|
||||
|
116
controllers/cert.go
Normal file
116
controllers/cert.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
// GetCerts
|
||||
// @Title GetCerts
|
||||
// @Tag Cert API
|
||||
// @Description get certs
|
||||
// @Param owner query string true "The owner of certs"
|
||||
// @Success 200 {array} object.Cert The Response object
|
||||
// @router /get-certs [get]
|
||||
func (c *ApiController) GetCerts() {
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetMaskedCerts(object.GetCerts(owner))
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCertCount(owner, field, value)))
|
||||
certs := object.GetMaskedCerts(object.GetPaginationCerts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||
c.ResponseOk(certs, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// @Title GetCert
|
||||
// @Tag Cert API
|
||||
// @Description get cert
|
||||
// @Param id query string true "The id of the cert"
|
||||
// @Success 200 {object} object.Cert The Response object
|
||||
// @router /get-cert [get]
|
||||
func (c *ApiController) GetCert() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetMaskedCert(object.GetCert(id))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title UpdateCert
|
||||
// @Tag Cert API
|
||||
// @Description update cert
|
||||
// @Param id query string true "The id of the cert"
|
||||
// @Param body body object.Cert true "The details of the cert"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-cert [post]
|
||||
func (c *ApiController) UpdateCert() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var cert object.Cert
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title AddCert
|
||||
// @Tag Cert API
|
||||
// @Description add cert
|
||||
// @Param body body object.Cert true "The details of the cert"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-cert [post]
|
||||
func (c *ApiController) AddCert() {
|
||||
var cert object.Cert
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddCert(&cert))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title DeleteCert
|
||||
// @Tag Cert API
|
||||
// @Description delete cert
|
||||
// @Param body body object.Cert true "The details of the cert"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-cert [post]
|
||||
func (c *ApiController) DeleteCert() {
|
||||
var cert object.Cert
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert))
|
||||
c.ServeJSON()
|
||||
}
|
@ -28,7 +28,7 @@ func (c *RootController) GetOidcDiscovery() {
|
||||
// @Tag OIDC API
|
||||
// @router /api/certs [get]
|
||||
func (c *RootController) GetOidcCert() {
|
||||
jwks, err := object.GetJSONWebKeySet()
|
||||
jwks, err := object.GetJsonWebKeySet()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
116
controllers/permission.go
Normal file
116
controllers/permission.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
// GetPermissions
|
||||
// @Title GetPermissions
|
||||
// @Tag Permission API
|
||||
// @Description get permissions
|
||||
// @Param owner query string true "The owner of permissions"
|
||||
// @Success 200 {array} object.Permission The Response object
|
||||
// @router /get-permissions [get]
|
||||
func (c *ApiController) GetPermissions() {
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetPermissions(owner)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetPermissionCount(owner, field, value)))
|
||||
permissions := object.GetPaginationPermissions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
c.ResponseOk(permissions, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// @Title GetPermission
|
||||
// @Tag Permission API
|
||||
// @Description get permission
|
||||
// @Param id query string true "The id of the permission"
|
||||
// @Success 200 {object} object.Permission The Response object
|
||||
// @router /get-permission [get]
|
||||
func (c *ApiController) GetPermission() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetPermission(id)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title UpdatePermission
|
||||
// @Tag Permission API
|
||||
// @Description update permission
|
||||
// @Param id query string true "The id of the permission"
|
||||
// @Param body body object.Permission true "The details of the permission"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-permission [post]
|
||||
func (c *ApiController) UpdatePermission() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var permission object.Permission
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title AddPermission
|
||||
// @Tag Permission API
|
||||
// @Description add permission
|
||||
// @Param body body object.Permission true "The details of the permission"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-permission [post]
|
||||
func (c *ApiController) AddPermission() {
|
||||
var permission object.Permission
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddPermission(&permission))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title DeletePermission
|
||||
// @Tag Permission API
|
||||
// @Description delete permission
|
||||
// @Param body body object.Permission true "The details of the permission"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-permission [post]
|
||||
func (c *ApiController) DeletePermission() {
|
||||
var permission object.Permission
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission))
|
||||
c.ServeJSON()
|
||||
}
|
@ -202,7 +202,7 @@ func (c *ApiController) UploadResource() {
|
||||
}
|
||||
|
||||
user.Avatar = fileUrl
|
||||
object.UpdateUser(user.GetId(), user, []string{"avatar"})
|
||||
object.UpdateUser(user.GetId(), user, []string{"avatar"}, false)
|
||||
case "termsOfUse":
|
||||
applicationId := fmt.Sprintf("admin/%s", parent)
|
||||
app := object.GetApplication(applicationId)
|
||||
|
116
controllers/role.go
Normal file
116
controllers/role.go
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
// GetRoles
|
||||
// @Title GetRoles
|
||||
// @Tag Role API
|
||||
// @Description get roles
|
||||
// @Param owner query string true "The owner of roles"
|
||||
// @Success 200 {array} object.Role The Response object
|
||||
// @router /get-roles [get]
|
||||
func (c *ApiController) GetRoles() {
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
if limit == "" || page == "" {
|
||||
c.Data["json"] = object.GetRoles(owner)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRoleCount(owner, field, value)))
|
||||
roles := object.GetPaginationRoles(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
c.ResponseOk(roles, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// @Title GetRole
|
||||
// @Tag Role API
|
||||
// @Description get role
|
||||
// @Param id query string true "The id of the role"
|
||||
// @Success 200 {object} object.Role The Response object
|
||||
// @router /get-role [get]
|
||||
func (c *ApiController) GetRole() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetRole(id)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title UpdateRole
|
||||
// @Tag Role API
|
||||
// @Description update role
|
||||
// @Param id query string true "The id of the role"
|
||||
// @Param body body object.Role true "The details of the role"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-role [post]
|
||||
func (c *ApiController) UpdateRole() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var role object.Role
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateRole(id, &role))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title AddRole
|
||||
// @Tag Role API
|
||||
// @Description add role
|
||||
// @Param body body object.Role true "The details of the role"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-role [post]
|
||||
func (c *ApiController) AddRole() {
|
||||
var role object.Role
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddRole(&role))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @Title DeleteRole
|
||||
// @Tag Role API
|
||||
// @Description delete role
|
||||
// @Param body body object.Role true "The details of the role"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-role [post]
|
||||
func (c *ApiController) DeleteRole() {
|
||||
var role object.Role
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteRole(&role))
|
||||
c.ServeJSON()
|
||||
}
|
@ -125,7 +125,8 @@ func (c *ApiController) UpdateUser() {
|
||||
columns = strings.Split(columnsStr, ",")
|
||||
}
|
||||
|
||||
affected := object.UpdateUser(id, &user, columns)
|
||||
isGlobalAdmin := c.IsGlobalAdmin()
|
||||
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
||||
if affected {
|
||||
object.UpdateUserToOriginalDatabase(&user)
|
||||
}
|
||||
@ -226,11 +227,6 @@ func (c *ApiController) SetPassword() {
|
||||
c.ResponseError("Please login first.")
|
||||
return
|
||||
}
|
||||
requestUser := object.GetUser(requestUserId)
|
||||
if requestUser == nil {
|
||||
c.ResponseError("Session outdated. Please login again.")
|
||||
return
|
||||
}
|
||||
|
||||
userId := fmt.Sprintf("%s/%s", userOwner, userName)
|
||||
targetUser := object.GetUser(userId)
|
||||
@ -240,7 +236,14 @@ func (c *ApiController) SetPassword() {
|
||||
}
|
||||
|
||||
hasPermission := false
|
||||
|
||||
if strings.HasPrefix(requestUserId, "app/") {
|
||||
hasPermission = true
|
||||
} else {
|
||||
requestUser := object.GetUser(requestUserId)
|
||||
if requestUser == nil {
|
||||
c.ResponseError("Session outdated. Please login again.")
|
||||
return
|
||||
}
|
||||
if requestUser.IsGlobalAdmin {
|
||||
hasPermission = true
|
||||
} else if requestUserId == userId {
|
||||
@ -248,7 +251,7 @@ func (c *ApiController) SetPassword() {
|
||||
} else if targetUser.Owner == requestUser.Owner && requestUser.IsAdmin {
|
||||
hasPermission = true
|
||||
}
|
||||
|
||||
}
|
||||
if !hasPermission {
|
||||
c.ResponseError("You don't have the permission to do this.")
|
||||
return
|
||||
@ -272,8 +275,6 @@ func (c *ApiController) SetPassword() {
|
||||
return
|
||||
}
|
||||
|
||||
c.SetSessionUsername("")
|
||||
|
||||
targetUser.Password = newPassword
|
||||
object.SetUserField(targetUser, "password", targetUser.Password)
|
||||
c.Data["json"] = Response{Status: "ok"}
|
||||
|
60
controllers/user_upload.go
Normal file
60
controllers/user_upload.go
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
func saveFile(path string, file *multipart.File) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, *file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ApiController) UploadUsers() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||
|
||||
file, header, err := c.Ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||
|
||||
path := util.GetUploadXlsxPath(fileId)
|
||||
util.EnsureFileFolderExists(path)
|
||||
saveFile(path, &file)
|
||||
|
||||
affected := object.UploadUsers(owner, fileId)
|
||||
if affected {
|
||||
c.ResponseOk()
|
||||
} else {
|
||||
c.ResponseError("Failed to import users")
|
||||
}
|
||||
}
|
3
go.mod
3
go.mod
@ -18,13 +18,14 @@ require (
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/jinzhu/configor v1.2.1 // indirect
|
||||
github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8
|
||||
github.com/mileusna/crontab v1.0.1
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russellhaering/gosaml2 v0.6.0
|
||||
github.com/russellhaering/goxmldsig v1.1.1
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/thanhpk/randstr v1.0.4
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
||||
|
6
go.sum
6
go.sum
@ -264,8 +264,6 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mileusna/crontab v1.0.1 h1:YrDLc7l3xOiznmXq2FtAgg+1YQ3yC6pfFVPe+ywXNtg=
|
||||
github.com/mileusna/crontab v1.0.1/go.mod h1:dbns64w/u3tUnGZGf8pAa76ZqOfeBX4olW4U1ZwExmc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -313,6 +311,8 @@ github.com/qiangmzsx/string-adapter/v2 v2.1.0 h1:q0y8TPa/sTwtriJPRe8gWL++PuZ+XbO
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0/go.mod h1:PElPB7b7HnGKTsuADAffFpOQXHqjEGJz1+U1a6yR5wA=
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76 h1:J2Xj92efYLxPl3BiibgEDEUiMsCBzwTurE/8JjD8CG4=
|
||||
github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76/go.mod h1:JhtPzUhP5KGtCB2yksmxuYAD4hEWw4qGQJpucjsm3U0=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
@ -349,6 +349,8 @@ github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2K
|
||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
|
||||
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154 h1:THBgwGwUQtsw6L53cSSA2wwL3sLrm+HJ3Dk+ye/lMCI=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
|
||||
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
|
||||
|
7
main.go
7
main.go
@ -15,6 +15,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/astaxie/beego/plugins/cors"
|
||||
@ -23,12 +25,13 @@ import (
|
||||
"github.com/casbin/casdoor/object"
|
||||
"github.com/casbin/casdoor/proxy"
|
||||
"github.com/casbin/casdoor/routers"
|
||||
|
||||
_ "github.com/casbin/casdoor/routers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
object.InitAdapter()
|
||||
createDatabase := flag.Bool("createDatabase", false, "true if you need casdoor to create database")
|
||||
flag.Parse()
|
||||
object.InitAdapter(*createDatabase)
|
||||
object.InitDb()
|
||||
object.InitDefaultStorageProvider()
|
||||
object.InitLdapAutoSynchronizer()
|
||||
|
@ -35,11 +35,15 @@ func InitConfig() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
InitAdapter()
|
||||
InitAdapter(true)
|
||||
}
|
||||
|
||||
func InitAdapter() {
|
||||
func InitAdapter(createDatabase bool) {
|
||||
|
||||
adapter = NewAdapter(beego.AppConfig.String("driverName"), conf.GetBeegoConfDataSourceName(), beego.AppConfig.String("dbName"))
|
||||
if createDatabase {
|
||||
adapter.CreateDatabase()
|
||||
}
|
||||
adapter.createTable()
|
||||
}
|
||||
|
||||
@ -75,6 +79,17 @@ func NewAdapter(driverName string, dataSourceName string, dbName string) *Adapte
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Adapter) CreateDatabase() error {
|
||||
engine, err := xorm.NewEngine(a.driverName, a.dataSourceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer engine.Close()
|
||||
|
||||
_, err = engine.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8 COLLATE utf8_general_ci", a.dbName))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) open() {
|
||||
dataSourceName := a.dataSourceName + a.dbName
|
||||
if a.driverName != "mysql" {
|
||||
@ -95,6 +110,9 @@ func (a *Adapter) close() {
|
||||
}
|
||||
|
||||
func (a *Adapter) createTable() {
|
||||
showSql, _ := beego.AppConfig.Bool("showSql")
|
||||
a.Engine.ShowSQL(showSql)
|
||||
|
||||
err := a.Engine.Sync2(new(Organization))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -105,6 +123,16 @@ func (a *Adapter) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Role))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Permission))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Provider))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -145,6 +173,11 @@ func (a *Adapter) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Cert))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Ldap))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -31,6 +31,7 @@ type Application struct {
|
||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||
EnablePassword bool `json:"enablePassword"`
|
||||
EnableSignUp bool `json:"enableSignUp"`
|
||||
EnableSigninSession bool `json:"enableSigninSession"`
|
||||
@ -88,7 +89,7 @@ func GetPaginationApplications(owner string, offset, limit int, field, value, so
|
||||
return applications
|
||||
}
|
||||
|
||||
func getApplicationsByOrganizationName(owner string, organization string) []*Application {
|
||||
func GetApplicationsByOrganizationName(owner string, organization string) []*Application {
|
||||
applications := []*Application{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Owner: owner, Organization: organization})
|
||||
if err != nil {
|
||||
@ -200,24 +201,37 @@ func GetApplicationByClientId(clientId string) *Application {
|
||||
}
|
||||
}
|
||||
|
||||
func GetApplicationByClientIdAndSecret(clientId, clientSecret string) *Application {
|
||||
if util.IsStrsEmpty(clientId, clientSecret) {
|
||||
return nil
|
||||
}
|
||||
|
||||
app := GetApplicationByClientId(clientId)
|
||||
if app == nil || app.ClientSecret != clientSecret {
|
||||
return nil
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func GetApplication(id string) *Application {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getApplication(owner, name)
|
||||
}
|
||||
|
||||
func GetMaskedApplication(application *Application, userId string) *Application {
|
||||
if isUserIdGlobalAdmin(userId) {
|
||||
return application
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if application.ClientSecret != "" {
|
||||
application.ClientSecret = "***"
|
||||
}
|
||||
return application
|
||||
}
|
||||
|
||||
func GetMaskedApplications(applications []*Application, userId string) []*Application {
|
||||
if isUserIdGlobalAdmin(userId) {
|
||||
return applications
|
||||
}
|
||||
|
||||
for _, application := range applications {
|
||||
application = GetMaskedApplication(application, userId)
|
||||
}
|
||||
return applications
|
||||
}
|
||||
|
||||
func UpdateApplication(id string, application *Application) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getApplication(owner, name) == nil {
|
||||
|
164
object/cert.go
Normal file
164
object/cert.go
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type Cert struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Scope string `xorm:"varchar(100)" json:"scope"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
CryptoAlgorithm string `xorm:"varchar(100)" json:"cryptoAlgorithm"`
|
||||
BitSize int `json:"bitSize"`
|
||||
ExpireInYears int `json:"expireInYears"`
|
||||
|
||||
PublicKey string `xorm:"mediumtext" json:"publicKey"`
|
||||
PrivateKey string `xorm:"mediumtext" json:"privateKey"`
|
||||
}
|
||||
|
||||
func GetMaskedCert(cert *Cert) *Cert {
|
||||
if cert == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return cert
|
||||
}
|
||||
|
||||
func GetMaskedCerts(certs []*Cert) []*Cert {
|
||||
for _, cert := range certs {
|
||||
cert = GetMaskedCert(cert)
|
||||
}
|
||||
return certs
|
||||
}
|
||||
|
||||
func GetCertCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
count, err := session.Count(&Cert{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return int(count)
|
||||
}
|
||||
|
||||
func GetCerts(owner string) []*Cert {
|
||||
certs := []*Cert{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&certs, &Cert{Owner: owner})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return certs
|
||||
}
|
||||
|
||||
func GetPaginationCerts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Cert {
|
||||
certs := []*Cert{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&certs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return certs
|
||||
}
|
||||
|
||||
func getCert(owner string, name string) *Cert {
|
||||
if owner == "" || name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
cert := Cert{Owner: owner, Name: name}
|
||||
existed, err := adapter.Engine.Get(&cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &cert
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetCert(id string) *Cert {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getCert(owner, name)
|
||||
}
|
||||
|
||||
func UpdateCert(id string, cert *Cert) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getCert(owner, name) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func AddCert(cert *Cert) bool {
|
||||
if cert.PublicKey == "" || cert.PrivateKey == "" {
|
||||
publicKey, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
|
||||
cert.PublicKey = publicKey
|
||||
cert.PrivateKey = privateKey
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.Insert(cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func DeleteCert(cert *Cert) bool {
|
||||
affected, err := adapter.Engine.ID(core.PK{cert.Owner, cert.Name}).Delete(&Cert{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func (p *Cert) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
||||
}
|
||||
|
||||
func getCertByApplication(application *Application) *Cert {
|
||||
if application.Cert != "" {
|
||||
return getCert("admin", application.Cert)
|
||||
} else {
|
||||
return GetDefaultCert()
|
||||
}
|
||||
}
|
||||
|
||||
func GetDefaultCert() *Cert {
|
||||
return getCert("admin", "cert-built-in")
|
||||
}
|
@ -14,12 +14,23 @@
|
||||
|
||||
package object
|
||||
|
||||
import "github.com/casbin/casdoor/util"
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
//go:embed token_jwt_key.pem
|
||||
var tokenJwtPublicKey string
|
||||
|
||||
//go:embed token_jwt_key.key
|
||||
var tokenJwtPrivateKey string
|
||||
|
||||
func InitDb() {
|
||||
initBuiltInOrganization()
|
||||
initBuiltInUser()
|
||||
initBuiltInApplication()
|
||||
initBuiltInCert()
|
||||
initBuiltInLdap()
|
||||
}
|
||||
|
||||
@ -90,6 +101,7 @@ func initBuiltInApplication() {
|
||||
Logo: "https://cdn.casbin.com/logo/logo_1024x256.png",
|
||||
HomepageUrl: "https://casdoor.org",
|
||||
Organization: "built-in",
|
||||
Cert: "cert-built-in",
|
||||
EnablePassword: true,
|
||||
EnableSignUp: true,
|
||||
Providers: []*ProviderItem{},
|
||||
@ -109,6 +121,28 @@ func initBuiltInApplication() {
|
||||
AddApplication(application)
|
||||
}
|
||||
|
||||
func initBuiltInCert() {
|
||||
cert := getCert("admin", "cert-built-in")
|
||||
if cert != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cert = &Cert{
|
||||
Owner: "admin",
|
||||
Name: "cert-built-in",
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
DisplayName: "Built-in Cert",
|
||||
Scope: "JWT",
|
||||
Type: "x509",
|
||||
CryptoAlgorithm: "RSA",
|
||||
BitSize: 4096,
|
||||
ExpireInYears: 20,
|
||||
PublicKey: tokenJwtPublicKey,
|
||||
PrivateKey: tokenJwtPrivateKey,
|
||||
}
|
||||
AddCert(cert)
|
||||
}
|
||||
|
||||
func initBuiltInLdap() {
|
||||
ldap := GetLdap("ldap-built-in")
|
||||
if ldap != nil {
|
||||
|
@ -72,17 +72,20 @@ func GetOidcDiscovery() OidcDiscovery {
|
||||
return oidcDiscovery
|
||||
}
|
||||
|
||||
func GetJSONWebKeySet() (jose.JSONWebKeySet, error) {
|
||||
func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
|
||||
cert := GetDefaultCert()
|
||||
|
||||
//follows the protocol rfc 7517(draft)
|
||||
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
||||
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
||||
certPEMBlock := []byte(tokenJwtPublicKey)
|
||||
certDERBlock, _ := pem.Decode(certPEMBlock)
|
||||
x509Cert, _ := x509.ParseCertificate(certDERBlock.Bytes)
|
||||
certPemBlock := []byte(cert.PublicKey)
|
||||
certDerBlock, _ := pem.Decode(certPemBlock)
|
||||
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)
|
||||
|
||||
var jwk jose.JSONWebKey
|
||||
jwk.Key = x509Cert.PublicKey
|
||||
jwk.Certificates = []*x509.Certificate{x509Cert}
|
||||
jwk.KeyID = cert.Name
|
||||
|
||||
var jwks jose.JSONWebKeySet
|
||||
jwks.Keys = []jose.JSONWebKey{jwk}
|
||||
|
@ -124,7 +124,7 @@ func UpdateOrganization(id string, organization *Organization) bool {
|
||||
}
|
||||
|
||||
if name != organization.Name {
|
||||
applications := getApplicationsByOrganizationName("admin", name)
|
||||
applications := GetApplicationsByOrganizationName("admin", name)
|
||||
for _, application := range applications {
|
||||
application.Organization = organization.Name
|
||||
UpdateApplication(application.GetId(), application)
|
||||
|
132
object/permission.go
Normal file
132
object/permission.go
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type Permission struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
|
||||
Users []string `xorm:"mediumtext" json:"users"`
|
||||
Roles []string `xorm:"mediumtext" json:"roles"`
|
||||
|
||||
ResourceType string `xorm:"varchar(100)" json:"resourceType"`
|
||||
Resources []string `xorm:"mediumtext" json:"resources"`
|
||||
Actions []string `xorm:"mediumtext" json:"actions"`
|
||||
Effect string `xorm:"varchar(100)" json:"effect"`
|
||||
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
}
|
||||
|
||||
func GetPermissionCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
count, err := session.Count(&Permission{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return int(count)
|
||||
}
|
||||
|
||||
func GetPermissions(owner string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
||||
func GetPaginationPermissions(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&permissions)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
||||
func getPermission(owner string, name string) *Permission {
|
||||
if owner == "" || name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
permission := Permission{Owner: owner, Name: name}
|
||||
existed, err := adapter.Engine.Get(&permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &permission
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetPermission(id string) *Permission {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getPermission(owner, name)
|
||||
}
|
||||
|
||||
func UpdatePermission(id string, permission *Permission) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getPermission(owner, name) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func AddPermission(permission *Permission) bool {
|
||||
affected, err := adapter.Engine.Insert(permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func DeletePermission(permission *Permission) bool {
|
||||
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func (permission *Permission) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", permission.Owner, permission.Name)
|
||||
}
|
@ -47,6 +47,8 @@ type Record struct {
|
||||
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
|
||||
Action string `xorm:"varchar(1000)" json:"action"`
|
||||
|
||||
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
||||
|
||||
IsTriggered bool `json:"isTriggered"`
|
||||
}
|
||||
|
||||
@ -159,6 +161,11 @@ func SendWebhooks(record *Record) error {
|
||||
}
|
||||
|
||||
if matched {
|
||||
if webhook.IsUserExtended {
|
||||
user := getUser(record.Organization, record.User)
|
||||
record.ExtendedUser = user
|
||||
}
|
||||
|
||||
err := sendWebhook(webhook, record)
|
||||
if err != nil {
|
||||
return err
|
||||
|
126
object/role.go
Normal file
126
object/role.go
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
|
||||
Users []string `xorm:"mediumtext" json:"users"`
|
||||
Roles []string `xorm:"mediumtext" json:"roles"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
}
|
||||
|
||||
func GetRoleCount(owner, field, value string) int {
|
||||
session := adapter.Engine.Where("owner=?", owner)
|
||||
if field != "" && value != "" {
|
||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||
}
|
||||
count, err := session.Count(&Role{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return int(count)
|
||||
}
|
||||
|
||||
func GetRoles(owner string) []*Role {
|
||||
roles := []*Role{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&roles, &Role{Owner: owner})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
func GetPaginationRoles(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Role {
|
||||
roles := []*Role{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&roles)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
func getRole(owner string, name string) *Role {
|
||||
if owner == "" || name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
role := Role{Owner: owner, Name: name}
|
||||
existed, err := adapter.Engine.Get(&role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &role
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetRole(id string) *Role {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getRole(owner, name)
|
||||
}
|
||||
|
||||
func UpdateRole(id string, role *Role) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getRole(owner, name) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func AddRole(role *Role) bool {
|
||||
affected, err := adapter.Engine.Insert(role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func DeleteRole(role *Role) bool {
|
||||
affected, err := adapter.Engine.ID(core.PK{role.Owner, role.Name}).Delete(&Role{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func (role *Role) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", role.Owner, role.Name)
|
||||
}
|
@ -48,6 +48,7 @@ type Syncer struct {
|
||||
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
||||
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
|
||||
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"`
|
||||
ErrorText string `xorm:"mediumtext" json:"errorText"`
|
||||
SyncInterval int `json:"syncInterval"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
|
||||
@ -140,6 +141,26 @@ func UpdateSyncer(id string, syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func updateSyncerErrorText(syncer *Syncer, line string) bool {
|
||||
s := getSyncer(syncer.Owner, syncer.Name)
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
s.ErrorText = s.ErrorText + line
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{s.Owner, s.Name}).Cols("error_text").Update(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
@ -149,6 +170,10 @@ func AddSyncer(syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
@ -158,6 +183,10 @@ func DeleteSyncer(syncer *Syncer) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if affected == 1 {
|
||||
deleteSyncerJob(syncer)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
|
@ -14,27 +14,56 @@
|
||||
|
||||
package object
|
||||
|
||||
import "github.com/mileusna/crontab"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
var cronMap map[string]*crontab.Crontab
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
var cronMap map[string]*cron.Cron
|
||||
|
||||
func init() {
|
||||
cronMap = map[string]*crontab.Crontab{}
|
||||
cronMap = map[string]*cron.Cron{}
|
||||
}
|
||||
|
||||
func getCrontab(name string) *crontab.Crontab {
|
||||
ctab, ok := cronMap[name]
|
||||
func getCronMap(name string) *cron.Cron {
|
||||
m, ok := cronMap[name]
|
||||
if !ok {
|
||||
ctab = crontab.New()
|
||||
cronMap[name] = ctab
|
||||
m = cron.New()
|
||||
cronMap[name] = m
|
||||
}
|
||||
return ctab
|
||||
return m
|
||||
}
|
||||
|
||||
func clearCrontab(name string) {
|
||||
ctab, ok := cronMap[name]
|
||||
func clearCron(name string) {
|
||||
cron, ok := cronMap[name]
|
||||
if ok {
|
||||
ctab.Clear()
|
||||
cron.Stop()
|
||||
delete(cronMap, name)
|
||||
}
|
||||
}
|
||||
|
||||
func addSyncerJob(syncer *Syncer) {
|
||||
deleteSyncerJob(syncer)
|
||||
|
||||
if !syncer.IsEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
syncer.initAdapter()
|
||||
|
||||
syncer.syncUsers()
|
||||
|
||||
schedule := fmt.Sprintf("@every %ds", syncer.SyncInterval)
|
||||
cron := getCronMap(syncer.Name)
|
||||
_, err := cron.AddFunc(schedule, syncer.syncUsers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cron.Start()
|
||||
}
|
||||
|
||||
func deleteSyncerJob(syncer *Syncer) {
|
||||
clearCron(syncer.Name)
|
||||
}
|
||||
|
@ -14,13 +14,25 @@
|
||||
|
||||
package object
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (syncer *Syncer) syncUsers() {
|
||||
fmt.Printf("Running syncUsers()..\n")
|
||||
|
||||
users, userMap := syncer.getUserMap()
|
||||
oUsers, oUserMap := syncer.getOriginalUserMap()
|
||||
oUsers, oUserMap, err := syncer.getOriginalUserMap()
|
||||
if err != nil {
|
||||
fmt.Printf(err.Error())
|
||||
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
|
||||
updateSyncerErrorText(syncer, line)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Users: %d, oUsers: %d\n", len(users), len(oUsers))
|
||||
|
||||
var affiliationMap map[int]string
|
||||
|
@ -25,42 +25,45 @@ import (
|
||||
|
||||
type OriginalUser = User
|
||||
|
||||
func (syncer *Syncer) getOriginalUsers() []*OriginalUser {
|
||||
func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) {
|
||||
sql := fmt.Sprintf("select * from %s", syncer.getTable())
|
||||
results, err := syncer.Adapter.Engine.QueryString(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return syncer.getOriginalUsersFromMap(results)
|
||||
return syncer.getOriginalUsersFromMap(results), nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*OriginalUser) {
|
||||
users := syncer.getOriginalUsers()
|
||||
func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*OriginalUser, error) {
|
||||
users, err := syncer.getOriginalUsers()
|
||||
if err != nil {
|
||||
return users, nil, err
|
||||
}
|
||||
|
||||
m := map[string]*OriginalUser{}
|
||||
for _, user := range users {
|
||||
m[user.Id] = user
|
||||
}
|
||||
return users, m
|
||||
return users, m, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) addUser(user *OriginalUser) bool {
|
||||
func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
|
||||
m := syncer.getMapFromOriginalUser(user)
|
||||
keyString, valueString := syncer.getSqlKeyValueStringFromMap(m)
|
||||
|
||||
sql := fmt.Sprintf("insert into %s (%s) values (%s)", syncer.getTable(), keyString, valueString)
|
||||
res, err := syncer.Adapter.Engine.Exec(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
/*func (syncer *Syncer) getOriginalColumns() []string {
|
||||
@ -84,7 +87,7 @@ func (syncer *Syncer) getCasdoorColumns() []string {
|
||||
return res
|
||||
}
|
||||
|
||||
func (syncer *Syncer) updateUser(user *OriginalUser) bool {
|
||||
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
|
||||
m := syncer.getMapFromOriginalUser(user)
|
||||
pkValue := m[syncer.TablePrimaryKey]
|
||||
delete(m, syncer.TablePrimaryKey)
|
||||
@ -93,22 +96,22 @@ func (syncer *Syncer) updateUser(user *OriginalUser) bool {
|
||||
sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, syncer.TablePrimaryKey, pkValue)
|
||||
res, err := syncer.Adapter.Engine.Exec(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) updateUserForOriginalFields(user *User) bool {
|
||||
func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(user.GetId())
|
||||
oldUser := getUserById(owner, name)
|
||||
if oldUser == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
||||
@ -119,10 +122,10 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) bool {
|
||||
columns = append(columns, "affiliation", "hash", "pre_hash")
|
||||
affected, err := adapter.Engine.ID(core.PK{oldUser.Owner, oldUser.Name}).Cols(columns...).Update(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) calculateHash(user *OriginalUser) string {
|
||||
@ -158,22 +161,7 @@ func (syncer *Syncer) initAdapter() {
|
||||
func RunSyncUsersJob() {
|
||||
syncers := GetSyncers("admin")
|
||||
for _, syncer := range syncers {
|
||||
if !syncer.IsEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
syncer.initAdapter()
|
||||
|
||||
syncer.syncUsers()
|
||||
|
||||
// run at every minute
|
||||
//schedule := fmt.Sprintf("* * * * %d", syncer.SyncInterval)
|
||||
schedule := "* * * * *"
|
||||
ctab := getCrontab(syncer.Name)
|
||||
err := ctab.AddJob(schedule, syncer.syncUsers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
addSyncerJob(syncer)
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(1<<63 - 1))
|
||||
|
@ -17,7 +17,6 @@ package object
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"xorm.io/core"
|
||||
@ -48,6 +47,7 @@ type Token struct {
|
||||
type TokenWrapper struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IdToken string `json:"id_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
@ -190,6 +190,12 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
|
||||
Code: "",
|
||||
}
|
||||
}
|
||||
if user.IsForbidden {
|
||||
return &Code{
|
||||
Message: "error: the user is forbidden to sign in, please contact the administrator",
|
||||
Code: "",
|
||||
}
|
||||
}
|
||||
|
||||
msg, application := CheckOAuthLogin(clientId, responseType, redirectUri, scope, state)
|
||||
if msg != "" {
|
||||
@ -286,6 +292,7 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: token.AccessToken,
|
||||
IdToken: token.AccessToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
TokenType: token.TokenType,
|
||||
ExpiresIn: token.ExpiresIn,
|
||||
Scope: token.Scope,
|
||||
@ -294,51 +301,65 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
|
||||
return tokenWrapper
|
||||
}
|
||||
|
||||
func RefreshToken(grantType string, refreshToken string, scope string, clientId string, clientSecret string) *Code {
|
||||
func RefreshToken(grantType string, refreshToken string, scope string, clientId string, clientSecret string) *TokenWrapper {
|
||||
// check parameters
|
||||
if grantType != "refresh_token" {
|
||||
return &Code{
|
||||
Message: "error: grant_type should be \"refresh_token\"",
|
||||
Code: "",
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: grant_type should be \"refresh_token\"",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
application := GetApplicationByClientId(clientId)
|
||||
if application == nil {
|
||||
return &Code{
|
||||
Message: "error: invalid client_id",
|
||||
Code: "",
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: invalid client_id",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
if application.ClientSecret != clientSecret {
|
||||
return &Code{
|
||||
Message: "error: invalid client_secret",
|
||||
Code: "",
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: invalid client_secret",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
// check whether the refresh token is valid, and has not expired.
|
||||
token := Token{RefreshToken: refreshToken}
|
||||
existed, err := adapter.Engine.Get(&token)
|
||||
if err != nil || !existed {
|
||||
return &Code{
|
||||
Message: "error: invalid refresh_token",
|
||||
Code: "",
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: invalid refresh_token",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
claims, err := ParseJwtToken(refreshToken)
|
||||
|
||||
cert := getCertByApplication(application)
|
||||
_, err = ParseJwtToken(refreshToken, cert)
|
||||
if err != nil {
|
||||
return &Code{
|
||||
Message: "error: invalid refresh_token",
|
||||
Code: "",
|
||||
}
|
||||
}
|
||||
if time.Now().Unix() > claims.ExpiresAt.Unix() {
|
||||
return &Code{
|
||||
Message: "error: expired refresh_token",
|
||||
Code: "",
|
||||
return &TokenWrapper{
|
||||
AccessToken: fmt.Sprintf("error: %s", err.Error()),
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
// generate a new token
|
||||
user := getUser(application.Owner, token.User)
|
||||
user := getUser(application.Organization, token.User)
|
||||
if user.IsForbidden {
|
||||
return &TokenWrapper{
|
||||
AccessToken: "error: the user is forbidden to sign in, please contact the administrator",
|
||||
TokenType: "",
|
||||
ExpiresIn: 0,
|
||||
Scope: "",
|
||||
}
|
||||
}
|
||||
newAccessToken, newRefreshToken, err := generateJwtToken(application, user, "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -360,8 +381,14 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
||||
}
|
||||
AddToken(newToken)
|
||||
|
||||
return &Code{
|
||||
Message: "",
|
||||
Code: token.Code,
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: token.AccessToken,
|
||||
IdToken: token.AccessToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
TokenType: token.TokenType,
|
||||
ExpiresIn: token.ExpiresIn,
|
||||
Scope: token.Scope,
|
||||
}
|
||||
|
||||
return tokenWrapper
|
||||
}
|
||||
|
@ -23,20 +23,41 @@ import (
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
)
|
||||
|
||||
//go:embed token_jwt_key.pem
|
||||
var tokenJwtPublicKey string
|
||||
|
||||
//go:embed token_jwt_key.key
|
||||
var tokenJwtPrivateKey string
|
||||
|
||||
type Claims struct {
|
||||
*User
|
||||
Name string `json:"name,omitempty"`
|
||||
Owner string `json:"owner,omitempty"`
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type UserShort struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
}
|
||||
|
||||
type ClaimsShort struct {
|
||||
*UserShort
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func getShortUser(user *User) *UserShort {
|
||||
res := &UserShort{
|
||||
Owner: user.Owner,
|
||||
Name: user.Name,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func getShortClaims(claims Claims) ClaimsShort {
|
||||
res := ClaimsShort{
|
||||
UserShort: getShortUser(claims.User),
|
||||
Nonce: claims.Nonce,
|
||||
RegisteredClaims: claims.RegisteredClaims,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generateJwtToken(application *Application, user *User, nonce string) (string, string, error) {
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
||||
@ -47,6 +68,8 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
||||
claims := Claims{
|
||||
User: user,
|
||||
Nonce: nonce,
|
||||
// FIXME: A workaround for custom claim by reusing `tag` in user info
|
||||
Tag: user.Tag,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: beego.AppConfig.String("origin"),
|
||||
Subject: user.Id,
|
||||
@ -57,24 +80,32 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
||||
ID: "",
|
||||
},
|
||||
}
|
||||
//all fields of the User struct are not added in "JWT-Empty" format
|
||||
|
||||
var token *jwt.Token
|
||||
var refreshToken *jwt.Token
|
||||
|
||||
// the JWT token length in "JWT-Empty" mode will be very short, as User object only has two properties: owner and name
|
||||
if application.TokenFormat == "JWT-Empty" {
|
||||
claims.User = nil
|
||||
}
|
||||
claims.Name = user.Name
|
||||
claims.Owner = user.Owner
|
||||
claimsShort := getShortClaims(claims)
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
||||
claimsShort.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
||||
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
||||
} else {
|
||||
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
||||
refreshToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
}
|
||||
|
||||
// Use "token_jwt_key.key" as RSA private key
|
||||
privateKey := tokenJwtPrivateKey
|
||||
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
|
||||
cert := getCertByApplication(application)
|
||||
|
||||
// RSA private key
|
||||
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(cert.PrivateKey))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
token.Header["kid"] = cert.Name
|
||||
tokenString, err := token.SignedString(key)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
@ -84,14 +115,14 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
||||
return tokenString, refreshTokenString, err
|
||||
}
|
||||
|
||||
func ParseJwtToken(token string) (*Claims, error) {
|
||||
func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
|
||||
t, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
// Use "token_jwt_key.pem" as RSA public key
|
||||
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(tokenJwtPublicKey))
|
||||
// RSA public key
|
||||
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(cert.PublicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -20,19 +20,14 @@ import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
func generateRsaKeys(fileId string) {
|
||||
func generateRsaKeys(bitSize int, expireInYears int, commonName string, organization string) (string, string) {
|
||||
// https://stackoverflow.com/questions/64104586/use-golang-to-get-rsa-key-the-same-way-openssl-genrsa
|
||||
// https://stackoverflow.com/questions/43822945/golang-can-i-create-x509keypair-using-rsa-key
|
||||
|
||||
bitSize := 4096
|
||||
|
||||
// Generate RSA key.
|
||||
key, err := rsa.GenerateKey(rand.Reader, bitSize)
|
||||
if err != nil {
|
||||
@ -50,12 +45,12 @@ func generateRsaKeys(fileId string) {
|
||||
tml := x509.Certificate{
|
||||
// you can add any attr that you need
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
||||
NotAfter: time.Now().AddDate(expireInYears, 0, 0),
|
||||
// you have to generate a different serial number each execution
|
||||
SerialNumber: big.NewInt(123456),
|
||||
Subject: pkix.Name{
|
||||
CommonName: "Casdoor Cert",
|
||||
Organization: []string{"Casdoor Organization"},
|
||||
CommonName: commonName,
|
||||
Organization: []string{organization},
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
@ -70,9 +65,5 @@ func generateRsaKeys(fileId string) {
|
||||
Bytes: cert,
|
||||
})
|
||||
|
||||
// Write private key to file.
|
||||
util.WriteBytesToPath(privateKeyPem, fmt.Sprintf("%s.key", fileId))
|
||||
|
||||
// Write certificate (aka public key) to file.
|
||||
util.WriteBytesToPath(certPem, fmt.Sprintf("%s.pem", fileId))
|
||||
return string(certPem), string(privateKeyPem)
|
||||
}
|
||||
|
@ -14,9 +14,20 @@
|
||||
|
||||
package object
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
func TestGenerateRsaKeys(t *testing.T) {
|
||||
fileId := "token_jwt_key"
|
||||
generateRsaKeys(fileId)
|
||||
publicKey, privateKey := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization")
|
||||
|
||||
// Write certificate (aka public key) to file.
|
||||
util.WriteStringToPath(publicKey, fmt.Sprintf("%s.pem", fileId))
|
||||
|
||||
// Write private key to file.
|
||||
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/util"
|
||||
"xorm.io/core"
|
||||
@ -27,21 +28,21 @@ type User struct {
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
|
||||
|
||||
Id string `xorm:"varchar(100)" json:"id"`
|
||||
Id string `xorm:"varchar(100) index" json:"id"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Avatar string `xorm:"varchar(500)" json:"avatar"`
|
||||
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
|
||||
Email string `xorm:"varchar(100)" json:"email"`
|
||||
Phone string `xorm:"varchar(100)" json:"phone"`
|
||||
Email string `xorm:"varchar(100) index" json:"email"`
|
||||
Phone string `xorm:"varchar(100) index" json:"phone"`
|
||||
Location string `xorm:"varchar(100)" json:"location"`
|
||||
Address []string `json:"address"`
|
||||
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
|
||||
Title string `xorm:"varchar(100)" json:"title"`
|
||||
IdCardType string `xorm:"varchar(100)" json:"idCardType"`
|
||||
IdCard string `xorm:"varchar(100)" json:"idCard"`
|
||||
IdCard string `xorm:"varchar(100) index" json:"idCard"`
|
||||
Homepage string `xorm:"varchar(100)" json:"homepage"`
|
||||
Bio string `xorm:"varchar(100)" json:"bio"`
|
||||
Tag string `xorm:"varchar(100)" json:"tag"`
|
||||
@ -269,7 +270,7 @@ func GetLastUser(owner string) *User {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateUser(id string, user *User, columns []string) bool {
|
||||
func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) bool {
|
||||
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
|
||||
oldUser := getUser(owner, name)
|
||||
if oldUser == nil {
|
||||
@ -284,9 +285,12 @@ func UpdateUser(id string, user *User, columns []string) bool {
|
||||
|
||||
if len(columns) == 0 {
|
||||
columns = []string{"owner", "display_name", "avatar",
|
||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag",
|
||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties"}
|
||||
}
|
||||
if isGlobalAdmin {
|
||||
columns = append(columns, "name")
|
||||
}
|
||||
|
||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
|
||||
if err != nil {
|
||||
@ -347,9 +351,10 @@ func AddUsers(users []*User) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
organization := GetOrganizationByUser(users[0])
|
||||
//organization := GetOrganizationByUser(users[0])
|
||||
for _, user := range users {
|
||||
user.UpdateUserPassword(organization)
|
||||
// this function is only used for syncer or batch upload, so no need to encrypt the password
|
||||
//user.UpdateUserPassword(organization)
|
||||
|
||||
user.UpdateUserHash()
|
||||
user.PreHash = user.Hash
|
||||
@ -407,3 +412,7 @@ func LinkUserAccount(user *User, field string, value string) bool {
|
||||
func (user *User) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", user.Owner, user.Name)
|
||||
}
|
||||
|
||||
func isUserIdGlobalAdmin(userId string) bool {
|
||||
return strings.HasPrefix(userId, "built-in/")
|
||||
}
|
||||
|
114
object/user_upload.go
Normal file
114
object/user_upload.go
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2021 The casbin 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 (
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/casbin/casdoor/xlsx"
|
||||
)
|
||||
|
||||
func getUserMap(owner string) map[string]*User {
|
||||
m := map[string]*User{}
|
||||
|
||||
users := GetUsers(owner)
|
||||
for _, user := range users {
|
||||
m[user.GetId()] = user
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func parseLineItem(line *[]string, i int) string {
|
||||
if i >= len(*line) {
|
||||
return ""
|
||||
} else {
|
||||
return (*line)[i]
|
||||
}
|
||||
}
|
||||
|
||||
func parseLineItemInt(line *[]string, i int) int {
|
||||
s := parseLineItem(line, i)
|
||||
return util.ParseInt(s)
|
||||
}
|
||||
|
||||
func parseLineItemBool(line *[]string, i int) bool {
|
||||
return parseLineItemInt(line, i) != 0
|
||||
}
|
||||
|
||||
func UploadUsers(owner string, fileId string) bool {
|
||||
table := xlsx.ReadXlsxFile(fileId)
|
||||
|
||||
oldUserMap := getUserMap(owner)
|
||||
newUsers := []*User{}
|
||||
for _, line := range table {
|
||||
if parseLineItem(&line, 0) == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Owner: parseLineItem(&line, 0),
|
||||
Name: parseLineItem(&line, 1),
|
||||
CreatedTime: parseLineItem(&line, 2),
|
||||
UpdatedTime: parseLineItem(&line, 3),
|
||||
Id: parseLineItem(&line, 4),
|
||||
Type: parseLineItem(&line, 5),
|
||||
Password: parseLineItem(&line, 6),
|
||||
PasswordSalt: parseLineItem(&line, 7),
|
||||
DisplayName: parseLineItem(&line, 8),
|
||||
Avatar: parseLineItem(&line, 9),
|
||||
PermanentAvatar: "",
|
||||
Email: parseLineItem(&line, 10),
|
||||
Phone: parseLineItem(&line, 11),
|
||||
Location: parseLineItem(&line, 12),
|
||||
Address: []string{parseLineItem(&line, 13)},
|
||||
Affiliation: parseLineItem(&line, 14),
|
||||
Title: parseLineItem(&line, 15),
|
||||
IdCardType: parseLineItem(&line, 16),
|
||||
IdCard: parseLineItem(&line, 17),
|
||||
Homepage: parseLineItem(&line, 18),
|
||||
Bio: parseLineItem(&line, 19),
|
||||
Tag: parseLineItem(&line, 20),
|
||||
Region: parseLineItem(&line, 21),
|
||||
Language: parseLineItem(&line, 22),
|
||||
Gender: parseLineItem(&line, 23),
|
||||
Birthday: parseLineItem(&line, 24),
|
||||
Education: parseLineItem(&line, 25),
|
||||
Score: parseLineItemInt(&line, 26),
|
||||
Ranking: parseLineItemInt(&line, 27),
|
||||
IsDefaultAvatar: false,
|
||||
IsOnline: parseLineItemBool(&line, 28),
|
||||
IsAdmin: parseLineItemBool(&line, 29),
|
||||
IsGlobalAdmin: parseLineItemBool(&line, 30),
|
||||
IsForbidden: parseLineItemBool(&line, 31),
|
||||
IsDeleted: parseLineItemBool(&line, 32),
|
||||
SignupApplication: parseLineItem(&line, 33),
|
||||
Hash: "",
|
||||
PreHash: "",
|
||||
CreatedIp: parseLineItem(&line, 34),
|
||||
LastSigninTime: parseLineItem(&line, 35),
|
||||
LastSigninIp: parseLineItem(&line, 36),
|
||||
Properties: map[string]string{},
|
||||
}
|
||||
|
||||
if _, ok := oldUserMap[user.GetId()]; !ok {
|
||||
newUsers = append(newUsers, user)
|
||||
}
|
||||
}
|
||||
|
||||
if len(newUsers) == 0 {
|
||||
return false
|
||||
}
|
||||
return AddUsersInBatch(newUsers)
|
||||
}
|
@ -64,6 +64,12 @@ func GetUserByFields(organization string, field string) *User {
|
||||
return user
|
||||
}
|
||||
|
||||
// check ID card
|
||||
user = GetUserByField(organization, "id_card", field)
|
||||
if user != nil {
|
||||
return user
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ type Webhook struct {
|
||||
ContentType string `xorm:"varchar(100)" json:"contentType"`
|
||||
Headers []*Header `xorm:"mediumtext" json:"headers"`
|
||||
Events []string `xorm:"varchar(100)" json:"events"`
|
||||
IsUserExtended bool `json:"isUserExtended"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
// "/page?access_token=123"
|
||||
accessToken := ctx.Input.Query("accessToken")
|
||||
if accessToken != "" {
|
||||
claims, err := object.ParseJwtToken(accessToken)
|
||||
cert := object.GetDefaultCert()
|
||||
claims, err := object.ParseJwtToken(accessToken, cert)
|
||||
if err != nil {
|
||||
responseError(ctx, "invalid JWT token")
|
||||
return
|
||||
@ -71,7 +72,8 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
// Authorization: Bearer bearerToken
|
||||
bearerToken := parseBearerToken(ctx)
|
||||
if bearerToken != "" {
|
||||
claims, err := object.ParseJwtToken(bearerToken)
|
||||
cert := object.GetDefaultCert()
|
||||
claims, err := object.ParseJwtToken(bearerToken, cert)
|
||||
if err != nil {
|
||||
responseError(ctx, err.Error())
|
||||
return
|
||||
|
@ -68,6 +68,19 @@ func initAPI() {
|
||||
beego.Router("/api/update-user", &controllers.ApiController{}, "POST:UpdateUser")
|
||||
beego.Router("/api/add-user", &controllers.ApiController{}, "POST:AddUser")
|
||||
beego.Router("/api/delete-user", &controllers.ApiController{}, "POST:DeleteUser")
|
||||
beego.Router("/api/upload-users", &controllers.ApiController{}, "POST:UploadUsers")
|
||||
|
||||
beego.Router("/api/get-roles", &controllers.ApiController{}, "GET:GetRoles")
|
||||
beego.Router("/api/get-role", &controllers.ApiController{}, "GET:GetRole")
|
||||
beego.Router("/api/update-role", &controllers.ApiController{}, "POST:UpdateRole")
|
||||
beego.Router("/api/add-role", &controllers.ApiController{}, "POST:AddRole")
|
||||
beego.Router("/api/delete-role", &controllers.ApiController{}, "POST:DeleteRole")
|
||||
|
||||
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
|
||||
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission")
|
||||
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
|
||||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
||||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
||||
|
||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||
@ -112,6 +125,7 @@ func initAPI() {
|
||||
beego.Router("/api/delete-token", &controllers.ApiController{}, "POST:DeleteToken")
|
||||
beego.Router("/api/login/oauth/code", &controllers.ApiController{}, "POST:GetOAuthCode")
|
||||
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
||||
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
||||
|
||||
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")
|
||||
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
|
||||
@ -128,6 +142,12 @@ func initAPI() {
|
||||
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
||||
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
||||
|
||||
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
|
||||
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
|
||||
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
|
||||
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
||||
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
||||
|
||||
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
||||
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
|
||||
|
||||
|
19
util/path.go
19
util/path.go
@ -18,6 +18,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -28,6 +29,24 @@ func FileExist(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func GetPath(path string) string {
|
||||
return filepath.Dir(path)
|
||||
}
|
||||
|
||||
func EnsureFileFolderExists(path string) {
|
||||
p := GetPath(path)
|
||||
if !FileExist(p) {
|
||||
err := os.MkdirAll(p, os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveExt(filename string) string {
|
||||
return filename[:len(filename)-len(filepath.Ext(filename))]
|
||||
}
|
||||
|
||||
func UrlJoin(base string, path string) string {
|
||||
res := fmt.Sprintf("%s/%s", strings.TrimRight(base, "/"), strings.TrimLeft(path, "/"))
|
||||
return res
|
||||
|
21
util/setting.go
Normal file
21
util/setting.go
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
|
||||
import "fmt"
|
||||
|
||||
func GetUploadXlsxPath(fileId string) string {
|
||||
return fmt.Sprintf("tmpFiles/%s.xlsx", fileId)
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
"codemirror": "^5.61.1",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"craco-less": "^1.17.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18n-iso-countries": "^7.0.0",
|
||||
"i18next": "^19.8.9",
|
||||
"moment": "^2.29.1",
|
||||
|
@ -23,12 +23,15 @@ import OrganizationListPage from "./OrganizationListPage";
|
||||
import OrganizationEditPage from "./OrganizationEditPage";
|
||||
import UserListPage from "./UserListPage";
|
||||
import UserEditPage from "./UserEditPage";
|
||||
import RoleListPage from "./RoleListPage";
|
||||
import RoleEditPage from "./RoleEditPage";
|
||||
import PermissionListPage from "./PermissionListPage";
|
||||
import PermissionEditPage from "./PermissionEditPage";
|
||||
import ProviderListPage from "./ProviderListPage";
|
||||
import ProviderEditPage from "./ProviderEditPage";
|
||||
import ApplicationListPage from "./ApplicationListPage";
|
||||
import ApplicationEditPage from "./ApplicationEditPage";
|
||||
import ResourceListPage from "./ResourceListPage";
|
||||
// import ResourceEditPage from "./ResourceEditPage";
|
||||
import LdapEditPage from "./LdapEditPage";
|
||||
import LdapSyncPage from "./LdapSyncPage";
|
||||
import TokenListPage from "./TokenListPage";
|
||||
@ -38,6 +41,8 @@ import WebhookListPage from "./WebhookListPage";
|
||||
import WebhookEditPage from "./WebhookEditPage";
|
||||
import SyncerListPage from "./SyncerListPage";
|
||||
import SyncerEditPage from "./SyncerEditPage";
|
||||
import CertListPage from "./CertListPage";
|
||||
import CertEditPage from "./CertEditPage";
|
||||
import AccountPage from "./account/AccountPage";
|
||||
import HomePage from "./basic/HomePage";
|
||||
import CustomGithubCorner from "./CustomGithubCorner";
|
||||
@ -101,6 +106,10 @@ class App extends Component {
|
||||
this.setState({ selectedMenuKey: '/organizations' });
|
||||
} else if (uri.includes('/users')) {
|
||||
this.setState({ selectedMenuKey: '/users' });
|
||||
} else if (uri.includes('/roles')) {
|
||||
this.setState({ selectedMenuKey: '/roles' });
|
||||
} else if (uri.includes('/permissions')) {
|
||||
this.setState({ selectedMenuKey: '/permissions' });
|
||||
} else if (uri.includes('/providers')) {
|
||||
this.setState({ selectedMenuKey: '/providers' });
|
||||
} else if (uri.includes('/applications')) {
|
||||
@ -115,6 +124,8 @@ class App extends Component {
|
||||
this.setState({ selectedMenuKey: '/webhooks' });
|
||||
} else if (uri.includes('/syncers')) {
|
||||
this.setState({ selectedMenuKey: '/syncers' });
|
||||
} else if (uri.includes('/certs')) {
|
||||
this.setState({ selectedMenuKey: '/certs' });
|
||||
} else if (uri.includes('/signup')) {
|
||||
this.setState({ selectedMenuKey: '/signup' });
|
||||
} else if (uri.includes('/login')) {
|
||||
@ -324,6 +335,20 @@ class App extends Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/roles">
|
||||
<Link to="/roles">
|
||||
{i18next.t("general:Roles")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/permissions">
|
||||
<Link to="/permissions">
|
||||
{i18next.t("general:Permissions")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/providers">
|
||||
<Link to="/providers">
|
||||
@ -376,6 +401,13 @@ class App extends Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/certs">
|
||||
<Link to="/certs">
|
||||
{i18next.t("general:Certs")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/swagger">
|
||||
<a target="_blank" rel="noreferrer" href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>
|
||||
@ -426,6 +458,10 @@ class App extends Component {
|
||||
<Route exact path="/organizations/:organizationName/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />}/>
|
||||
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/providers/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)}/>
|
||||
@ -440,6 +476,8 @@ class App extends Component {
|
||||
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/certs/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />}/>
|
||||
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
||||
|
@ -21,7 +21,6 @@ import * as Setting from "./Setting";
|
||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
|
||||
class ApplicationListPage extends BaseListPage {
|
||||
|
||||
|
254
web/src/CertEditPage.js
Normal file
254
web/src/CertEditPage.js
Normal file
@ -0,0 +1,254 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select} from 'antd';
|
||||
import * as CertBackend from "./backend/CertBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import copy from "copy-to-clipboard";
|
||||
import FileSaver from "file-saver";
|
||||
|
||||
const { Option } = Select;
|
||||
const { TextArea } = Input;
|
||||
|
||||
class CertEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
certName: props.match.params.certName,
|
||||
cert: null,
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getCert();
|
||||
}
|
||||
|
||||
getCert() {
|
||||
CertBackend.getCert("admin", this.state.certName)
|
||||
.then((cert) => {
|
||||
this.setState({
|
||||
cert: cert,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseCertField(key, value) {
|
||||
if (["port"].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
updateCertField(key, value) {
|
||||
value = this.parseCertField(key, value);
|
||||
|
||||
let cert = this.state.cert;
|
||||
cert[key] = value;
|
||||
this.setState({
|
||||
cert: cert,
|
||||
});
|
||||
}
|
||||
|
||||
renderCert() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("cert:Edit Cert")}
|
||||
<Button onClick={() => this.submitCertEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.cert.name} onChange={e => {
|
||||
this.updateCertField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.cert.displayName} onChange={e => {
|
||||
this.updateCertField('displayName', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Scope"), i18next.t("cert:Scope - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.cert.scope} onChange={(value => {
|
||||
this.updateCertField('scope', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'JWT', name: 'JWT'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.cert.type} onChange={(value => {
|
||||
this.updateCertField('type', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'x509', name: 'x509'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Crypto algorithm"), i18next.t("cert:Crypto algorithm - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.cert.cryptoAlgorithm} onChange={(value => {
|
||||
this.updateCertField('cryptoAlgorithm', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'RSA', name: 'RSA'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Bit size"), i18next.t("cert:Bit size - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={this.state.cert.bitSize} onChange={value => {
|
||||
this.updateCertField('bitSize', value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Expire in years"), i18next.t("cert:Expire in years - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={this.state.cert.expireInYears} onChange={value => {
|
||||
this.updateCertField('expireInYears', value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Public key"), i18next.t("cert:Public key - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={9} >
|
||||
<Button style={{marginRight: '10px', marginBottom: '10px'}} onClick={() => {
|
||||
copy(this.state.cert.publicKey);
|
||||
Setting.showMessage("success", i18next.t("cert:Public key copied to clipboard successfully"));
|
||||
}}
|
||||
>
|
||||
{i18next.t("cert:Copy public key")}
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => {
|
||||
const blob = new Blob([this.state.cert.publicKey], {type: "text/plain;charset=utf-8"});
|
||||
FileSaver.saveAs(blob, "token_jwt_key.pem");
|
||||
}}
|
||||
>
|
||||
{i18next.t("cert:Download public key")}
|
||||
</Button>
|
||||
<TextArea autoSize={{minRows: 30, maxRows: 30}} value={this.state.cert.publicKey} onChange={e => {
|
||||
this.updateCertField('publicKey', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
<Col span={1} />
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("cert:Private key"), i18next.t("cert:Private key - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={9} >
|
||||
<Button style={{marginRight: '10px', marginBottom: '10px'}} onClick={() => {
|
||||
copy(this.state.cert.privateKey);
|
||||
Setting.showMessage("success", i18next.t("cert:Private key copied to clipboard successfully"));
|
||||
}}
|
||||
>
|
||||
{i18next.t("cert:Copy private key")}
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => {
|
||||
const blob = new Blob([this.state.cert.privateKey], {type: "text/plain;charset=utf-8"});
|
||||
FileSaver.saveAs(blob, "token_jwt_key.key");
|
||||
}}
|
||||
>
|
||||
{i18next.t("cert:Download private key")}
|
||||
</Button>
|
||||
<TextArea autoSize={{minRows: 30, maxRows: 30}} value={this.state.cert.privateKey} onChange={e => {
|
||||
this.updateCertField('privateKey', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
submitCertEdit(willExist) {
|
||||
let cert = Setting.deepCopy(this.state.cert);
|
||||
CertBackend.updateCert(this.state.cert.owner, this.state.certName, cert)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", `Successfully saved`);
|
||||
this.setState({
|
||||
certName: this.state.cert.name,
|
||||
});
|
||||
|
||||
if (willExist) {
|
||||
this.props.history.push(`/certs`);
|
||||
} else {
|
||||
this.props.history.push(`/certs/${this.state.cert.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
this.updateCertField('name', this.state.certName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.cert !== null ? this.renderCert() : null
|
||||
}
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitCertEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CertEditPage;
|
230
web/src/CertListPage.js
Normal file
230
web/src/CertListPage.js
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Popconfirm, Table} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as CertBackend from "./backend/CertBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
|
||||
class CertListPage extends BaseListPage {
|
||||
|
||||
newCert() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "admin", // this.props.account.certname,
|
||||
name: `cert_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Cert - ${randomName}`,
|
||||
scope: "JWT",
|
||||
type: "x509",
|
||||
cryptoAlgorithm: "RSA",
|
||||
bitSize: 4096,
|
||||
expireInYears: 20,
|
||||
publicKey: "",
|
||||
privateKey: "",
|
||||
}
|
||||
}
|
||||
|
||||
addCert() {
|
||||
const newCert = this.newCert();
|
||||
CertBackend.addCert(newCert)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Cert added successfully`);
|
||||
this.props.history.push(`/certs/${newCert.name}`);
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteCert(i) {
|
||||
CertBackend.deleteCert(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Cert deleted successfully`);
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Cert failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(certs) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '120px',
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('name'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/certs/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '180px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
dataIndex: 'displayName',
|
||||
key: 'displayName',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('displayName'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("cert:Scope"),
|
||||
dataIndex: 'scope',
|
||||
key: 'scope',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: 'JWT', value: 'JWT'},
|
||||
],
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("cert:Type"),
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: 'x509', value: 'x509'},
|
||||
],
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("cert:Crypto algorithm"),
|
||||
dataIndex: 'cryptoAlgorithm',
|
||||
key: 'cryptoAlgorithm',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: 'RSA', value: 'RSA'},
|
||||
],
|
||||
width: '190px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("cert:Bit size"),
|
||||
dataIndex: 'bitSize',
|
||||
key: 'bitSize',
|
||||
width: '130px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('bitSize'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("cert:Expire in years"),
|
||||
dataIndex: 'expireInYears',
|
||||
key: 'expireInYears',
|
||||
width: '170px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('expireInYears'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: '',
|
||||
key: 'op',
|
||||
width: '170px',
|
||||
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => this.props.history.push(`/certs/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete cert: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteCert(index)}
|
||||
>
|
||||
<Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const paginationProps = {
|
||||
total: this.state.pagination.total,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table scroll={{x: 'max-content'}} columns={columns} dataSource={certs} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Certs")}
|
||||
<Button type="primary" size="small" onClick={this.addCert.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
onChange={this.handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.category !== undefined && params.category !== null) {
|
||||
field = "category";
|
||||
value = params.category;
|
||||
} else if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({ loading: true });
|
||||
CertBackend.getCerts("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
pagination: {
|
||||
...params.pagination,
|
||||
total: res.data2,
|
||||
},
|
||||
searchText: params.searchText,
|
||||
searchedColumn: params.searchedColumn,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default CertListPage;
|
@ -59,7 +59,7 @@ export const PasswordModal = (props) => {
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Button type="default" onClick={showModal}>
|
||||
<Button type="default" disabled={props.disabled} onClick={showModal}>
|
||||
{ hasOldPassword ? i18next.t("user:Modify password...") : i18next.t("user:Set password...")}
|
||||
</Button>
|
||||
<Modal
|
||||
|
276
web/src/PermissionEditPage.js
Normal file
276
web/src/PermissionEditPage.js
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row, Select, Switch} from 'antd';
|
||||
import * as PermissionBackend from "./backend/PermissionBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as UserBackend from "./backend/UserBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import * as RoleBackend from "./backend/RoleBackend";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class PermissionEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
permissionName: props.match.params.permissionName,
|
||||
permission: null,
|
||||
organizations: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getPermission();
|
||||
this.getOrganizations();
|
||||
}
|
||||
|
||||
getPermission() {
|
||||
PermissionBackend.getPermission(this.state.organizationName, this.state.permissionName)
|
||||
.then((permission) => {
|
||||
this.setState({
|
||||
permission: permission,
|
||||
});
|
||||
|
||||
this.getUsers(permission.owner);
|
||||
this.getRoles(permission.owner);
|
||||
});
|
||||
}
|
||||
|
||||
getOrganizations() {
|
||||
OrganizationBackend.getOrganizations("admin")
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
organizations: (res.msg === undefined) ? res : [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getUsers(organizationName) {
|
||||
UserBackend.getUsers(organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
users: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getRoles(organizationName) {
|
||||
RoleBackend.getRoles(organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
roles: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parsePermissionField(key, value) {
|
||||
if ([""].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
updatePermissionField(key, value) {
|
||||
value = this.parsePermissionField(key, value);
|
||||
|
||||
let permission = this.state.permission;
|
||||
permission[key] = value;
|
||||
this.setState({
|
||||
permission: permission,
|
||||
});
|
||||
}
|
||||
|
||||
renderPermission() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("permission:Edit Permission")}
|
||||
<Button onClick={() => this.submitPermissionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.permission.owner} onChange={(owner => {
|
||||
this.updatePermissionField('owner', owner);
|
||||
|
||||
this.getUsers(owner);
|
||||
this.getRoles(owner);
|
||||
})}>
|
||||
{
|
||||
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.permission.name} onChange={e => {
|
||||
this.updatePermissionField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.permission.displayName} onChange={e => {
|
||||
this.updatePermissionField('displayName', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub users"), i18next.t("role:Sub users - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.permission.users} onChange={(value => {this.updatePermissionField('users', value);})}>
|
||||
{
|
||||
this.state.users.map((user, index) => <Option key={index} value={`${user.owner}/${user.name}`}>{`${user.owner}/${user.name}`}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub roles"), i18next.t("role:Sub roles - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.permission.roles} onChange={(value => {this.updatePermissionField('roles', value);})}>
|
||||
{
|
||||
this.state.roles.filter(roles => (roles.owner !== this.state.roles.owner || roles.name !== this.state.roles.name)).map((permission, index) => <Option key={index} value={`${permission.owner}/${permission.name}`}>{`${permission.owner}/${permission.name}`}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Resource type"), i18next.t("permission:Resource type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.permission.resourceType} onChange={(value => {
|
||||
this.updatePermissionField('resourceType', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'Application', name: 'Application'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Actions"), i18next.t("permission:Actions - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.permission.actions} onChange={(value => {
|
||||
this.updatePermissionField('actions', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'Read', name: 'Read'},
|
||||
{id: 'Write', name: 'Write'},
|
||||
{id: 'Admin', name: 'Admin'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Effect"), i18next.t("permission:Effect - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.permission.effect} onChange={(value => {
|
||||
this.updatePermissionField('effect', value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: 'Allow', name: 'Allow'},
|
||||
{id: 'Deny', name: 'Deny'},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.permission.isEnabled} onChange={checked => {
|
||||
this.updatePermissionField('isEnabled', checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
submitPermissionEdit(willExist) {
|
||||
let permission = Setting.deepCopy(this.state.permission);
|
||||
PermissionBackend.updatePermission(this.state.organizationName, this.state.permissionName, permission)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", `Successfully saved`);
|
||||
this.setState({
|
||||
permissionName: this.state.permission.name,
|
||||
});
|
||||
|
||||
if (willExist) {
|
||||
this.props.history.push(`/permissions`);
|
||||
} else {
|
||||
this.props.history.push(`/permissions/${this.state.permission.owner}/${this.state.permission.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
this.updatePermissionField('name', this.state.permissionName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.permission !== null ? this.renderPermission() : null
|
||||
}
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitPermissionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PermissionEditPage;
|
271
web/src/PermissionListPage.js
Normal file
271
web/src/PermissionListPage.js
Normal file
@ -0,0 +1,271 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Popconfirm, Switch, Table} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as PermissionBackend from "./backend/PermissionBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
|
||||
class PermissionListPage extends BaseListPage {
|
||||
newPermission() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "built-in",
|
||||
name: `permission_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Permission - ${randomName}`,
|
||||
users: [],
|
||||
roles: [],
|
||||
resourceType: "Application",
|
||||
resources: ["app-built-in"],
|
||||
action: "Read",
|
||||
effect: "Allow",
|
||||
isEnabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
addPermission() {
|
||||
const newPermission = this.newPermission();
|
||||
PermissionBackend.addPermission(newPermission)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Permission added successfully`);
|
||||
this.props.history.push(`/permissions/${newPermission.owner}/${newPermission.name}`);
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deletePermission(i) {
|
||||
PermissionBackend.deletePermission(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Permission deleted successfully`);
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Permission failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(permissions) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('owner'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/organizations/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '150px',
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('name'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/permissions/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
dataIndex: 'displayName',
|
||||
key: 'displayName',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('displayName'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub users"),
|
||||
dataIndex: 'users',
|
||||
key: 'users',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('users'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub roles"),
|
||||
dataIndex: 'roles',
|
||||
key: 'roles',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('roles'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Resource type"),
|
||||
dataIndex: 'resourceType',
|
||||
key: 'resourceType',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: 'Application', value: 'Application'},
|
||||
],
|
||||
width: '170px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Resources"),
|
||||
dataIndex: 'resources',
|
||||
key: 'resources',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('resources'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Actions"),
|
||||
dataIndex: 'actions',
|
||||
key: 'actions',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('actions'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Effect"),
|
||||
dataIndex: 'effect',
|
||||
key: 'effect',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: 'Allow', value: 'Allow'},
|
||||
{text: 'Deny', value: 'Deny'},
|
||||
],
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Is enabled"),
|
||||
dataIndex: 'isEnabled',
|
||||
key: 'isEnabled',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: '',
|
||||
key: 'op',
|
||||
width: '170px',
|
||||
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => this.props.history.push(`/permissions/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete permission: ${record.name} ?`}
|
||||
onConfirm={() => this.deletePermission(index)}
|
||||
>
|
||||
<Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const paginationProps = {
|
||||
total: this.state.pagination.total,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table scroll={{x: 'max-content'}} columns={columns} dataSource={permissions} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Permissions")}
|
||||
<Button type="primary" size="small" onClick={this.addPermission.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
onChange={this.handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({ loading: true });
|
||||
PermissionBackend.getPermissions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
pagination: {
|
||||
...params.pagination,
|
||||
total: res.data2,
|
||||
},
|
||||
searchText: params.searchText,
|
||||
searchedColumn: params.searchedColumn,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default PermissionListPage;
|
@ -119,14 +119,14 @@ class ProviderListPage extends BaseListPage {
|
||||
{text: 'Storage', value: 'Storage'},
|
||||
{text: 'SAML', value: 'SAML'},
|
||||
],
|
||||
width: '100px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Type"),
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
width: '80px',
|
||||
width: '110px',
|
||||
align: 'center',
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
@ -152,13 +152,6 @@ class ProviderListPage extends BaseListPage {
|
||||
return Setting.getShortText(text);
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: 'Client secret',
|
||||
// dataIndex: 'clientSecret',
|
||||
// key: 'clientSecret',
|
||||
// width: '150px',
|
||||
// sorter: (a, b) => a.clientSecret.localeCompare(b.clientSecret),
|
||||
// },
|
||||
{
|
||||
title: i18next.t("provider:Provider URL"),
|
||||
dataIndex: 'providerUrl',
|
||||
|
@ -20,7 +20,6 @@ import * as RecordBackend from "./backend/RecordBackend";
|
||||
import i18next from "i18next";
|
||||
import moment from "moment";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
|
||||
class RecordListPage extends BaseListPage {
|
||||
|
||||
@ -92,7 +91,7 @@ class RecordListPage extends BaseListPage {
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: 'organization',
|
||||
key: 'organization',
|
||||
width: '80px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('organization'),
|
||||
render: (text, record, index) => {
|
||||
@ -122,7 +121,7 @@ class RecordListPage extends BaseListPage {
|
||||
title: i18next.t("general:Method"),
|
||||
dataIndex: 'method',
|
||||
key: 'method',
|
||||
width: '100px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
|
@ -17,7 +17,7 @@ import i18next from "i18next";
|
||||
import React from "react";
|
||||
import * as Setting from "./Setting"
|
||||
import * as UserBackend from "./backend/UserBackend"
|
||||
import {CountDownInput} from "./component/CountDownInput";
|
||||
import {CountDownInput} from "./common/CountDownInput";
|
||||
import {MailOutlined, PhoneOutlined} from "@ant-design/icons";
|
||||
|
||||
export const ResetModal = (props) => {
|
||||
|
@ -21,7 +21,6 @@ import * as ResourceBackend from "./backend/ResourceBackend";
|
||||
import i18next from "i18next";
|
||||
import {Link} from "react-router-dom";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
|
||||
class ResourceListPage extends BaseListPage {
|
||||
constructor(props) {
|
||||
|
219
web/src/RoleEditPage.js
Normal file
219
web/src/RoleEditPage.js
Normal file
@ -0,0 +1,219 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row, Select, Switch} from 'antd';
|
||||
import * as RoleBackend from "./backend/RoleBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as UserBackend from "./backend/UserBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class RoleEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
roleName: props.match.params.roleName,
|
||||
role: null,
|
||||
organizations: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getRole();
|
||||
this.getOrganizations();
|
||||
}
|
||||
|
||||
getRole() {
|
||||
RoleBackend.getRole(this.state.organizationName, this.state.roleName)
|
||||
.then((role) => {
|
||||
this.setState({
|
||||
role: role,
|
||||
});
|
||||
|
||||
this.getUsers(role.owner);
|
||||
this.getRoles(role.owner);
|
||||
});
|
||||
}
|
||||
|
||||
getOrganizations() {
|
||||
OrganizationBackend.getOrganizations("admin")
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
organizations: (res.msg === undefined) ? res : [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getUsers(organizationName) {
|
||||
UserBackend.getUsers(organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
users: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getRoles(organizationName) {
|
||||
RoleBackend.getRoles(organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
roles: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseRoleField(key, value) {
|
||||
if ([""].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
updateRoleField(key, value) {
|
||||
value = this.parseRoleField(key, value);
|
||||
|
||||
let role = this.state.role;
|
||||
role[key] = value;
|
||||
this.setState({
|
||||
role: role,
|
||||
});
|
||||
}
|
||||
|
||||
renderRole() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("role:Edit Role")}
|
||||
<Button onClick={() => this.submitRoleEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" onClick={() => this.submitRoleEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.role.owner} onChange={(value => {this.updateRoleField('owner', value);})}>
|
||||
{
|
||||
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.role.name} onChange={e => {
|
||||
this.updateRoleField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.role.displayName} onChange={e => {
|
||||
this.updateRoleField('displayName', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub users"), i18next.t("role:Sub users - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.role.users} onChange={(value => {this.updateRoleField('users', value);})}>
|
||||
{
|
||||
this.state.users.map((user, index) => <Option key={index} value={`${user.owner}/${user.name}`}>{`${user.owner}/${user.name}`}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub roles"), i18next.t("role:Sub roles - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: '100%'}} value={this.state.role.roles} onChange={(value => {this.updateRoleField('roles', value);})}>
|
||||
{
|
||||
this.state.roles.filter(role => (role.owner !== this.state.role.owner || role.name !== this.state.role.name)).map((role, index) => <Option key={index} value={`${role.owner}/${role.name}`}>{`${role.owner}/${role.name}`}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.role.isEnabled} onChange={checked => {
|
||||
this.updateRoleField('isEnabled', checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
submitRoleEdit(willExist) {
|
||||
let role = Setting.deepCopy(this.state.role);
|
||||
RoleBackend.updateRole(this.state.organizationName, this.state.roleName, role)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
Setting.showMessage("success", `Successfully saved`);
|
||||
this.setState({
|
||||
roleName: this.state.role.name,
|
||||
});
|
||||
|
||||
if (willExist) {
|
||||
this.props.history.push(`/roles`);
|
||||
} else {
|
||||
this.props.history.push(`/roles/${this.state.role.owner}/${this.state.role.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
this.updateRoleField('name', this.state.roleName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.role !== null ? this.renderRole() : null
|
||||
}
|
||||
<div style={{marginTop: '20px', marginLeft: '40px'}}>
|
||||
<Button size="large" onClick={() => this.submitRoleEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: '20px'}} type="primary" size="large" onClick={() => this.submitRoleEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RoleEditPage;
|
222
web/src/RoleListPage.js
Normal file
222
web/src/RoleListPage.js
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Popconfirm, Switch, Table} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as RoleBackend from "./backend/RoleBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
|
||||
class RoleListPage extends BaseListPage {
|
||||
newRole() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "built-in",
|
||||
name: `role_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Role - ${randomName}`,
|
||||
users: [],
|
||||
roles: [],
|
||||
isEnabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
addRole() {
|
||||
const newRole = this.newRole();
|
||||
RoleBackend.addRole(newRole)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Role added successfully`);
|
||||
this.props.history.push(`/roles/${newRole.owner}/${newRole.name}`);
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteRole(i) {
|
||||
RoleBackend.deleteRole(this.state.data[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Role deleted successfully`);
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Role failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(roles) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('owner'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/organizations/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '150px',
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('name'),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/roles/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
dataIndex: 'displayName',
|
||||
key: 'displayName',
|
||||
width: '200px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('displayName'),
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub users"),
|
||||
dataIndex: 'users',
|
||||
key: 'users',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('users'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub roles"),
|
||||
dataIndex: 'roles',
|
||||
key: 'roles',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('roles'),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Is enabled"),
|
||||
dataIndex: 'isEnabled',
|
||||
key: 'isEnabled',
|
||||
width: '120px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: '',
|
||||
key: 'op',
|
||||
width: '170px',
|
||||
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => this.props.history.push(`/roles/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete role: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteRole(index)}
|
||||
>
|
||||
<Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const paginationProps = {
|
||||
total: this.state.pagination.total,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table scroll={{x: 'max-content'}} columns={columns} dataSource={roles} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Roles")}
|
||||
<Button type="primary" size="small" onClick={this.addRole.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
onChange={this.handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({ loading: true });
|
||||
RoleBackend.getRoles("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
pagination: {
|
||||
...params.pagination,
|
||||
total: res.data2,
|
||||
},
|
||||
searchText: params.searchText,
|
||||
searchedColumn: params.searchedColumn,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default RoleListPage;
|
@ -590,7 +590,7 @@ export function getNewRowNameForTable(table, rowName) {
|
||||
}
|
||||
|
||||
export function getTagColor(s) {
|
||||
return "success";
|
||||
return "processing";
|
||||
}
|
||||
|
||||
export function getTags(tags) {
|
||||
|
@ -74,6 +74,7 @@ class SignupTable extends React.Component {
|
||||
{id: 'Display name', name: 'Display name'},
|
||||
{id: 'Affiliation', name: 'Affiliation'},
|
||||
{id: 'Country/Region', name: 'Country/Region'},
|
||||
{id: 'ID card', name: 'ID card'},
|
||||
{id: 'Email', name: 'Email'},
|
||||
{id: 'Password', name: 'Password'},
|
||||
{id: 'Confirm password', name: 'Confirm password'},
|
||||
|
@ -21,6 +21,11 @@ import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import SyncerTableColumnTable from "./SyncerTableColumnTable";
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2';
|
||||
import "codemirror/lib/codemirror.css";
|
||||
require('codemirror/theme/material-darker.css');
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class SyncerEditPage extends React.Component {
|
||||
@ -248,6 +253,22 @@ class SyncerEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("syncer:Error text"), i18next.t("syncer:Error text - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<div style={{width: "100%", height: "300px"}} >
|
||||
<CodeMirror
|
||||
value={this.state.syncer.errorText}
|
||||
options={{mode: 'javascript', theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateSyncerField("errorText", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
|
@ -20,7 +20,6 @@ import * as Setting from "./Setting";
|
||||
import * as SyncerBackend from "./backend/SyncerBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
|
||||
class SyncerListPage extends BaseListPage {
|
||||
|
||||
@ -42,7 +41,7 @@ class SyncerListPage extends BaseListPage {
|
||||
tableColumns: [],
|
||||
affiliationTable: "",
|
||||
avatarBaseUrl: "",
|
||||
syncInterval: 1,
|
||||
syncInterval: 10,
|
||||
isEnabled: true,
|
||||
}
|
||||
}
|
||||
@ -112,7 +111,7 @@ class SyncerListPage extends BaseListPage {
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '180px',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
@ -187,7 +186,7 @@ class SyncerListPage extends BaseListPage {
|
||||
title: i18next.t("syncer:Sync interval"),
|
||||
dataIndex: 'syncInterval',
|
||||
key: 'syncInterval',
|
||||
width: '120px',
|
||||
width: '130px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('syncInterval'),
|
||||
},
|
||||
|
@ -176,7 +176,7 @@ class TokenListPage extends BaseListPage {
|
||||
title: i18next.t("token:Scope"),
|
||||
dataIndex: 'scope',
|
||||
key: 'scope',
|
||||
width: '100px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('scope'),
|
||||
},
|
||||
|
@ -25,11 +25,11 @@ import PasswordModal from "./PasswordModal";
|
||||
import ResetModal from "./ResetModal";
|
||||
import AffiliationSelect from "./common/AffiliationSelect";
|
||||
import OAuthWidget from "./common/OAuthWidget";
|
||||
import SamlWidget from "./common/SamlWidget";
|
||||
import SelectRegionBox from "./SelectRegionBox";
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2';
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import SamlWidget from "./common/SamlWidget";
|
||||
require('codemirror/theme/material-darker.css');
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
@ -45,12 +45,14 @@ class UserEditPage extends React.Component {
|
||||
user: null,
|
||||
application: null,
|
||||
organizations: [],
|
||||
applications: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getUser();
|
||||
this.getOrganizations();
|
||||
this.getApplicationsByOrganization(this.state.organizationName);
|
||||
this.getUserApplication();
|
||||
}
|
||||
|
||||
@ -72,6 +74,15 @@ class UserEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getApplicationsByOrganization(organizationName) {
|
||||
ApplicationBackend.getApplicationsByOrganization("admin", organizationName)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
applications: (res.msg === undefined) ? res : [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getUserApplication() {
|
||||
ApplicationBackend.getUserApplication(this.state.organizationName, this.state.userName)
|
||||
.then((application) => {
|
||||
@ -140,7 +151,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.user.name} disabled={true} onChange={e => {
|
||||
<Input value={this.state.user.name} disabled={!Setting.isAdminUser(this.props.account)} onChange={e => {
|
||||
this.updateUserField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
@ -203,7 +214,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<PasswordModal user={this.state.user} account={this.props.account} />
|
||||
<PasswordModal user={this.state.user} account={this.props.account} disabled={this.state.userName !== this.state.user.name} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
@ -293,6 +304,18 @@ class UserEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Signup application"), i18next.t("general:Signup application - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} disabled={!Setting.isAdminUser(this.props.account)} value={this.state.user.signupApplication} onChange={(value => {this.updateUserField('signupApplication', value);})}>
|
||||
{
|
||||
this.state.applications.map((application, index) => <Option key={index} value={application.name}>{application.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
!this.isSelfOrAdmin() ? null : (
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
|
@ -14,13 +14,13 @@
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, Popconfirm, Switch, Table} from 'antd';
|
||||
import {Button, Popconfirm, Switch, Table, Upload} from 'antd';
|
||||
import {UploadOutlined} from "@ant-design/icons";
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as UserBackend from "./backend/UserBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
|
||||
class UserListPage extends BaseListPage {
|
||||
constructor(props) {
|
||||
@ -93,6 +93,43 @@ class UserListPage extends BaseListPage {
|
||||
});
|
||||
}
|
||||
|
||||
uploadFile(info) {
|
||||
const { status, response: res } = info.file;
|
||||
if (status === 'done') {
|
||||
if (res.status === 'ok') {
|
||||
Setting.showMessage("success", `Users uploaded successfully, refreshing the page`);
|
||||
|
||||
const { pagination } = this.state;
|
||||
this.fetch({ pagination });
|
||||
} else {
|
||||
Setting.showMessage("error", `Users failed to upload: ${res.msg}`);
|
||||
}
|
||||
} else if (status === 'error') {
|
||||
Setting.showMessage("error", `File failed to upload`);
|
||||
}
|
||||
}
|
||||
|
||||
renderUpload() {
|
||||
const props = {
|
||||
name: 'file',
|
||||
accept: '.xlsx',
|
||||
method: 'post',
|
||||
action: `${Setting.ServerUrl}/api/upload-users`,
|
||||
withCredentials: true,
|
||||
onChange: (info) => {
|
||||
this.uploadFile(info);
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Upload {...props}>
|
||||
<Button type="primary" size="small">
|
||||
<UploadOutlined /> {i18next.t("user:Upload (.xlsx)")}
|
||||
</Button>
|
||||
</Upload>
|
||||
)
|
||||
}
|
||||
|
||||
renderTable(users) {
|
||||
// transfer country code to name based on selected language
|
||||
var countries = require("i18n-iso-countries");
|
||||
@ -138,7 +175,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: (Setting.isMobile()) ? "80px" : "100px",
|
||||
width: (Setting.isMobile()) ? "80px" : "110px",
|
||||
fixed: 'left',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('name'),
|
||||
@ -164,7 +201,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("general:Display name"),
|
||||
dataIndex: 'displayName',
|
||||
key: 'displayName',
|
||||
width: '100px',
|
||||
// width: '100px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('displayName'),
|
||||
},
|
||||
@ -215,7 +252,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("user:Affiliation"),
|
||||
dataIndex: 'affiliation',
|
||||
key: 'affiliation',
|
||||
width: '120px',
|
||||
width: '140px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('affiliation'),
|
||||
},
|
||||
@ -223,7 +260,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("user:Country/Region"),
|
||||
dataIndex: 'region',
|
||||
key: 'region',
|
||||
width: '120px',
|
||||
width: '140px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('region'),
|
||||
},
|
||||
@ -231,7 +268,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("user:Tag"),
|
||||
dataIndex: 'tag',
|
||||
key: 'tag',
|
||||
width: '100px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('tag'),
|
||||
},
|
||||
@ -251,7 +288,7 @@ class UserListPage extends BaseListPage {
|
||||
title: i18next.t("user:Is global admin"),
|
||||
dataIndex: 'isGlobalAdmin',
|
||||
key: 'isGlobalAdmin',
|
||||
width: '110px',
|
||||
width: '140px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
@ -318,7 +355,10 @@ class UserListPage extends BaseListPage {
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Users")}
|
||||
<Button type="primary" size="small" onClick={this.addUser.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={this.addUser.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
{
|
||||
this.renderUpload()
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
|
@ -21,8 +21,73 @@ import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import WebhookHeaderTable from "./WebhookHeaderTable";
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2';
|
||||
import "codemirror/lib/codemirror.css";
|
||||
require('codemirror/theme/material-darker.css');
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const previewTemplate = {
|
||||
"id": 9078,
|
||||
"owner": "built-in",
|
||||
"name": "68f55b28-7380-46b1-9bde-64fe1576e3b3",
|
||||
"createdTime": "2022-01-01T01:03:42+08:00",
|
||||
"organization": "built-in",
|
||||
"clientIp": "159.89.126.192",
|
||||
"user": "admin",
|
||||
"method": "POST",
|
||||
"requestUri": "/api/login",
|
||||
"action": "login",
|
||||
"isTriggered": false,
|
||||
};
|
||||
|
||||
const userTemplate = {
|
||||
"owner": "built-in",
|
||||
"name": "admin",
|
||||
"createdTime": "2020-07-16T21:46:52+08:00",
|
||||
"updatedTime": "",
|
||||
"id": "9eb20f79-3bb5-4e74-99ac-39e3b9a171e8",
|
||||
"type": "normal-user",
|
||||
"password": "123",
|
||||
"passwordSalt": "",
|
||||
"displayName": "Admin",
|
||||
"avatar": "https://cdn.casbin.com/usercontent/admin/avatar/1596241359.png",
|
||||
"permanentAvatar": "https://cdn.casbin.com/casdoor/avatar/casbin/admin.png",
|
||||
"email": "admin@example.com",
|
||||
"phone": "",
|
||||
"location": "",
|
||||
"address": null,
|
||||
"affiliation": "",
|
||||
"title": "",
|
||||
"score": 10000,
|
||||
"ranking": 10,
|
||||
"isOnline": false,
|
||||
"isAdmin": true,
|
||||
"isGlobalAdmin": false,
|
||||
"isForbidden": false,
|
||||
"isDeleted": false,
|
||||
"signupApplication": "app-casnode",
|
||||
"properties": {
|
||||
"bio": "",
|
||||
"checkinDate": "20200801",
|
||||
"editorType": "",
|
||||
"emailVerifiedTime": "2020-07-16T21:46:52+08:00",
|
||||
"fileQuota": "50",
|
||||
"location": "",
|
||||
"no": "22",
|
||||
"oauth_QQ_displayName": "",
|
||||
"oauth_QQ_verifiedTime": "",
|
||||
"oauth_WeChat_displayName": "",
|
||||
"oauth_WeChat_verifiedTime": "",
|
||||
"onlineStatus": "false",
|
||||
"phoneVerifiedTime": "",
|
||||
"renameQuota": "3",
|
||||
"tagline": "",
|
||||
"website": ""
|
||||
}
|
||||
};
|
||||
|
||||
class WebhookEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -75,6 +140,12 @@ class WebhookEditPage extends React.Component {
|
||||
}
|
||||
|
||||
renderWebhook() {
|
||||
let preview = Setting.deepCopy(previewTemplate);
|
||||
if (this.state.webhook.isUserExtended) {
|
||||
preview["extendedUser"] = userTemplate;
|
||||
}
|
||||
const previewText = JSON.stringify(preview, null, 2);
|
||||
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
@ -181,6 +252,30 @@ class WebhookEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("webhook:Is user extended"), i18next.t("webhook:Is user extended - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.webhook.isUserExtended} onChange={checked => {
|
||||
this.updateWebhookField('isUserExtended', checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Preview"), i18next.t("general:Preview - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<div style={{width: "900px", height: "300px"}} >
|
||||
<CodeMirror
|
||||
value={previewText}
|
||||
options={{mode: 'javascript', theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
|
@ -72,7 +72,7 @@ class WebhookListPage extends BaseListPage {
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: 'organization',
|
||||
key: 'organization',
|
||||
width: '80px',
|
||||
width: '110px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps('organization'),
|
||||
render: (text, record, index) => {
|
||||
@ -157,6 +157,18 @@ class WebhookListPage extends BaseListPage {
|
||||
return Setting.getTags(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("webhook:Is user extended"),
|
||||
dataIndex: 'isUserExtended',
|
||||
key: 'isUserExtended',
|
||||
width: '160px',
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Is enabled"),
|
||||
dataIndex: 'isEnabled',
|
||||
|
@ -19,7 +19,7 @@ import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||
import * as Util from "./Util";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {CountDownInput} from "../component/CountDownInput";
|
||||
import {CountDownInput} from "../common/CountDownInput";
|
||||
import * as UserBackend from "../backend/UserBackend";
|
||||
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
|
||||
import CustomGithubCorner from "../CustomGithubCorner";
|
||||
|
@ -38,7 +38,7 @@ import AppleLoginButton from "./AppleLoginButton"
|
||||
import AzureADLoginButton from "./AzureADLoginButton";
|
||||
import SlackLoginButton from "./SlackLoginButton";
|
||||
import CustomGithubCorner from "../CustomGithubCorner";
|
||||
import {CountDownInput} from "../component/CountDownInput";
|
||||
import {CountDownInput} from "../common/CountDownInput";
|
||||
|
||||
class LoginPage extends React.Component {
|
||||
constructor(props) {
|
||||
@ -448,6 +448,8 @@ class LoginPage extends React.Component {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<span style={{float: "left"}}>
|
||||
{
|
||||
!application.enableCodeSignin ? null : (
|
||||
<a onClick={() => {
|
||||
this.setState({
|
||||
isCodeSignin: !this.state.isCodeSignin,
|
||||
@ -455,6 +457,8 @@ class LoginPage extends React.Component {
|
||||
}}>
|
||||
{this.state.isCodeSignin ? i18next.t("login:Sign in with password") : i18next.t("login:Sign in with code")}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
<span style={{float: "right"}}>
|
||||
{i18next.t("login:No account?")}
|
||||
|
@ -21,7 +21,7 @@ import i18next from "i18next";
|
||||
import * as Util from "./Util";
|
||||
import {authConfig} from "./Auth";
|
||||
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||
import {CountDownInput} from "../component/CountDownInput";
|
||||
import {CountDownInput} from "../common/CountDownInput";
|
||||
import SelectRegionBox from "../SelectRegionBox";
|
||||
import CustomGithubCorner from "../CustomGithubCorner";
|
||||
|
||||
@ -225,6 +225,28 @@ class SignupPage extends React.Component {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
)
|
||||
} else if (signupItem.name === "ID card") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="idCard"
|
||||
key="idCard"
|
||||
label={i18next.t("user:ID card")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: i18next.t("signup:Please input your ID card number!"),
|
||||
whitespace: true,
|
||||
},
|
||||
{
|
||||
required: required,
|
||||
pattern: new RegExp(/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9X]$/, "g"),
|
||||
message: i18next.t("signup:Please input the correct ID card number!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
)
|
||||
} else if (signupItem.name === "Country/Region") {
|
||||
return (
|
||||
<Form.Item
|
||||
|
@ -21,6 +21,13 @@ export function getApplications(owner, page = "", pageSize = "", field = "", val
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getApplicationsByOrganization(owner, organization) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&organization=${organization}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getApplication(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-application?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
|
56
web/src/backend/CertBackend.js
Normal file
56
web/src/backend/CertBackend.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getCerts(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-certs?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getCert(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-cert?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updateCert(owner, name, cert) {
|
||||
let newCert = Setting.deepCopy(cert);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-cert?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newCert),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addCert(cert) {
|
||||
let newCert = Setting.deepCopy(cert);
|
||||
return fetch(`${Setting.ServerUrl}/api/add-cert`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newCert),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deleteCert(cert) {
|
||||
let newCert = Setting.deepCopy(cert);
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-cert`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newCert),
|
||||
}).then(res => res.json());
|
||||
}
|
56
web/src/backend/PermissionBackend.js
Normal file
56
web/src/backend/PermissionBackend.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getPermissions(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-permissions?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getPermission(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-permission?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updatePermission(owner, name, permission) {
|
||||
let newPermission = Setting.deepCopy(permission);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-permission?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newPermission),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addPermission(permission) {
|
||||
let newPermission = Setting.deepCopy(permission);
|
||||
return fetch(`${Setting.ServerUrl}/api/add-permission`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newPermission),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deletePermission(permission) {
|
||||
let newPermission = Setting.deepCopy(permission);
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-permission`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newPermission),
|
||||
}).then(res => res.json());
|
||||
}
|
56
web/src/backend/RoleBackend.js
Normal file
56
web/src/backend/RoleBackend.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getRoles(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-roles?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getRole(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-role?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updateRole(owner, name, role) {
|
||||
let newRole = Setting.deepCopy(role);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-role?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newRole),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addRole(role) {
|
||||
let newRole = Setting.deepCopy(role);
|
||||
return fetch(`${Setting.ServerUrl}/api/add-role`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newRole),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deleteRole(role) {
|
||||
let newRole = Setting.deepCopy(role);
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-role`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(newRole),
|
||||
}).then(res => res.json());
|
||||
}
|
@ -1,431 +1,484 @@
|
||||
{
|
||||
"account": {
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"My Account": "My Account",
|
||||
"Settings for your account": "Settings for your account",
|
||||
"Sign Up": "Sign Up"
|
||||
"Login": "Anmelden",
|
||||
"Logout": "Abmelden",
|
||||
"My Account": "Mein Konto",
|
||||
"Settings for your account": "Einstellungen für Ihr Konto",
|
||||
"Sign Up": "Registrieren"
|
||||
},
|
||||
"application": {
|
||||
"Edit Application": "Edit Application",
|
||||
"Enable code signin": "Enable code signin",
|
||||
"Enable code signin - Tooltip": "Enable code signin - Tooltip",
|
||||
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
|
||||
"Enable signup": "Enable signup",
|
||||
"Edit Application": "Anwendung bearbeiten",
|
||||
"Enable code signin": "Code-Anmeldung aktivieren",
|
||||
"Enable code signin - Tooltip": "Aktiviere Codeanmeldung - Tooltip",
|
||||
"Enable signin session - Tooltip": "Aktiviere Anmeldesession - Tooltip",
|
||||
"Enable signup": "Anmeldung aktivieren",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Password ON": "Password ON",
|
||||
"File uploaded successfully": "Datei erfolgreich hochgeladen",
|
||||
"Password ON": "Passwort AN",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Redirect URL": "Redirect URL",
|
||||
"Redirect URLs": "Redirect URLs",
|
||||
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei",
|
||||
"Redirect URL": "Weiterleitungs-URL",
|
||||
"Redirect URLs": "Umleitungs-URLs",
|
||||
"Redirect URLs - Tooltip": "List of redirect addresses after successful login",
|
||||
"Refresh token expire": "Refresh token expire",
|
||||
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Refresh token expire": "Aktualisierungs-Token läuft ab",
|
||||
"Refresh token expire - Tooltip": "Aktualisierungs-Token läuft ab - Tooltip",
|
||||
"Signin session": "Anmeldesitzung",
|
||||
"Signup items": "Artikel registrieren",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Test prompt page..": "Test prompt page..",
|
||||
"Test signin page..": "Test signin page..",
|
||||
"Test signup page..": "Test signup page..",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Test prompt page..": "Test-Nachfrageseite..",
|
||||
"Test signin page..": "Anmeldeseite testen..",
|
||||
"Test signup page..": "Anmeldeseite testen..",
|
||||
"Token expire": "Token läuft ab",
|
||||
"Token expire - Tooltip": "Token läuft ab - Tooltip",
|
||||
"Token format": "Token-Format",
|
||||
"Token format - Tooltip": "Token-Format - Tooltip"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bitgröße",
|
||||
"Bit size - Tooltip": "Bit Größe - Tooltip",
|
||||
"Copy private key": "Privaten Schlüssel kopieren",
|
||||
"Copy public key": "Öffentlichen Schlüssel kopieren",
|
||||
"Crypto algorithm": "Crypto-Algorithmus",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "Privaten Schlüssel herunterladen",
|
||||
"Download public key": "Öffentlichen Schlüssel herunterladen",
|
||||
"Edit Cert": "Zitat bearbeiten",
|
||||
"Expire in years": "Gültig in Jahren",
|
||||
"Expire in years - Tooltip": "Verfällt in Jahren - Tooltip",
|
||||
"Private key": "Privater Schlüssel",
|
||||
"Private key - Tooltip": "Privater Schlüssel - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Privater Schlüssel erfolgreich in die Zwischenablage kopiert",
|
||||
"Public key": "Öffentlicher Schlüssel",
|
||||
"Public key - Tooltip": "Öffentlicher Schlüssel - Tooltip",
|
||||
"Public key copied to clipboard successfully": "Öffentlicher Schlüssel erfolgreich in die Zwischenablage kopiert",
|
||||
"Scope": "Bereich",
|
||||
"Scope - Tooltip": "Bereich - Tooltip",
|
||||
"Type": "Typ",
|
||||
"Type - Tooltip": "Typ - Tooltip"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
"Empty Code": "Empty Code",
|
||||
"Enter your code": "Enter your code",
|
||||
"Phone code": "Phone code",
|
||||
"Please input your phone verification code!": "Please input your phone verification code!",
|
||||
"Please input your verification code!": "Please input your verification code!",
|
||||
"Send Code": "Send Code",
|
||||
"Sending Code": "Sending Code",
|
||||
"Submit and complete": "Submit and complete"
|
||||
"Code You Received": "Code, den Sie erhalten haben",
|
||||
"Email code": "E-Mail-Code",
|
||||
"Empty Code": "Leerer Code",
|
||||
"Enter your code": "Geben Sie Ihren Code ein",
|
||||
"Phone code": "Telefoncode",
|
||||
"Please input your phone verification code!": "Bitte geben Sie Ihren Telefon-Verifizierungscode ein!",
|
||||
"Please input your verification code!": "Bitte geben Sie Ihren Bestätigungscode ein!",
|
||||
"Send Code": "Code senden",
|
||||
"Sending Code": "Code wird gesendet",
|
||||
"Submit and complete": "Absenden und abschließen"
|
||||
},
|
||||
"forget": {
|
||||
"Account": "Account",
|
||||
"Change Password": "Change Password",
|
||||
"Choose email or phone": "Choose email or phone",
|
||||
"Confirm": "Confirm",
|
||||
"Next Step": "Next Step",
|
||||
"Password": "Password",
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Account": "Konto",
|
||||
"Change Password": "Passwort ändern",
|
||||
"Choose email or phone": "E-Mail oder Telefon auswählen",
|
||||
"Confirm": "Bestätigen",
|
||||
"Next Step": "Nächster Schritt",
|
||||
"Password": "Passwort",
|
||||
"Please input your username!": "Bitte geben Sie Ihren Benutzernamen ein!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Verify": "Verify"
|
||||
"Retrieve password": "Passwort abrufen",
|
||||
"Verify": "Überprüfen"
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Action": "Aktion",
|
||||
"Add": "Neu",
|
||||
"Affiliation URL": "Affiliation-URL",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
"Application": "Application",
|
||||
"Applications": "Applications",
|
||||
"Applications that require authentication": "Applications that require authentication",
|
||||
"Application": "Anwendung",
|
||||
"Applications": "Anwendungen",
|
||||
"Applications that require authentication": "Anwendungen, die eine Authentifizierung benötigen",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Back Home": "Zurück zu Hause",
|
||||
"Captcha": "Captcha",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
"Certs": "Certs",
|
||||
"Client IP": "Client-IP",
|
||||
"Created time": "Erstellte Zeit",
|
||||
"Default avatar": "Standard Avatar",
|
||||
"Default avatar - Tooltip": "default avatar",
|
||||
"Delete": "Delete",
|
||||
"Description": "Description",
|
||||
"Delete": "Löschen",
|
||||
"Description": "Beschreibung",
|
||||
"Description - Tooltip": "Related descriptive information",
|
||||
"Display name": "Display name",
|
||||
"Display name": "Anzeigename",
|
||||
"Display name - Tooltip": "Name shown to users, repeatable",
|
||||
"Down": "Down",
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Down": "Unten",
|
||||
"Edit": "Bearbeiten",
|
||||
"Email": "E-Mail",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL": "URL vergessen",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Home",
|
||||
"Home": "Zuhause",
|
||||
"Home - Tooltip": "Application homepage",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "random string",
|
||||
"Is enabled": "Is enabled",
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"Is enabled": "Ist aktiviert",
|
||||
"Is enabled - Tooltip": "Ist aktiviert - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Method": "Method",
|
||||
"Master password": "Master-Passwort",
|
||||
"Master password - Tooltip": "Masterpasswort - Tooltip",
|
||||
"Method": "Methode",
|
||||
"Name": "Name",
|
||||
"Name - Tooltip": "Unique string-style identifier",
|
||||
"OAuth providers": "OAuth providers",
|
||||
"Organization": "Organization",
|
||||
"OAuth providers": "OAuth-Anbieter",
|
||||
"Organization": "Organisation",
|
||||
"Organization - Tooltip": "The group the user belongs to",
|
||||
"Organizations": "Organizations",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Organizations": "Organisationen",
|
||||
"Password": "Passwort",
|
||||
"Password - Tooltip": "Passwort - Tooltip",
|
||||
"Password salt": "Passwort-Salz",
|
||||
"Password salt - Tooltip": "Random parameters used for password encryption",
|
||||
"Password type": "Password type",
|
||||
"Password type": "Passworttyp",
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Permissions": "Berechtigungen",
|
||||
"Personal name": "Persönlicher Name",
|
||||
"Phone": "Telefon",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix": "Telefonpräfix",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Preview",
|
||||
"Preview": "Vorschau",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Provider": "Provider",
|
||||
"Providers": "Providers",
|
||||
"Provider": "Anbieter",
|
||||
"Providers": "Anbieter",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Records": "Records",
|
||||
"Records": "Datensätze",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Resources": "Ressourcen",
|
||||
"Roles": "Rollen",
|
||||
"Save": "Speichern",
|
||||
"Save & Exit": "Speichern & Beenden",
|
||||
"Signin URL": "Anmelde-URL",
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL": "Registrierungs-URL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Timestamp": "Zeitstempel",
|
||||
"Tokens": "Token",
|
||||
"URL": "URL",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
"User containers": "User containers",
|
||||
"User type": "User type",
|
||||
"Up": "Hoch",
|
||||
"User": "Benutzer",
|
||||
"User - Tooltip": "Benutzer - Tooltip",
|
||||
"User containers": "Benutzerbehälter",
|
||||
"User type": "Benutzertyp",
|
||||
"User type - Tooltip": "Permission role owned by the user",
|
||||
"Users": "Users",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Users": "Benutzer",
|
||||
"Users under all organizations": "Benutzer unter allen Organisationen",
|
||||
"Webhooks": "Webhooks",
|
||||
"{total} in total": "{total} in total"
|
||||
"{total} in total": "{total} insgesamt"
|
||||
},
|
||||
"ldap": {
|
||||
"Address": "Address",
|
||||
"Address": "Adresse",
|
||||
"Admin": "Admin",
|
||||
"Admin - Tooltip": "LDAP server admin CN or ID",
|
||||
"Admin Password": "Admin Password",
|
||||
"Admin Password": "Admin-Passwort",
|
||||
"Admin Password - Tooltip": "LDAP server admin password",
|
||||
"Auto Sync": "Auto Sync",
|
||||
"Auto Sync": "Auto-Sync",
|
||||
"Auto Sync - Tooltip": "Auto sync config, disable if is 0",
|
||||
"Base DN": "Base DN",
|
||||
"Base DN": "Basis-DN",
|
||||
"Base DN - Tooltip": "LDAP search base DN",
|
||||
"CN": "CN",
|
||||
"Edit LDAP": "Edit LDAP",
|
||||
"Email": "Email",
|
||||
"Group Id": "Group Id",
|
||||
"CN": "KN",
|
||||
"Edit LDAP": "LDAP bearbeiten",
|
||||
"Email": "E-Mail",
|
||||
"Group Id": "Gruppen Id",
|
||||
"ID": "ID",
|
||||
"Last Sync": "Last Sync",
|
||||
"Phone": "Phone",
|
||||
"Last Sync": "Letzter Sync",
|
||||
"Phone": "Telefon",
|
||||
"Server": "Server",
|
||||
"Server Host": "Server Host",
|
||||
"Server Host - Tooltip": "LDAP server host",
|
||||
"Server Name": "Server Name",
|
||||
"Server Name": "Servername",
|
||||
"Server Name - Tooltip": "LDAP server config display name",
|
||||
"Server Port": "Server Port",
|
||||
"Server Port": "Serverport",
|
||||
"Server Port - Tooltip": "LDAP server port",
|
||||
"Sync": "Sync",
|
||||
"The Auto Sync option will sync all users to specify organization": "The Auto Sync option will sync all users to specify organization",
|
||||
"UidNumber / Uid": "UidNumber / Uid"
|
||||
"The Auto Sync option will sync all users to specify organization": "Die Auto Sync Option wird alle Benutzer synchronisieren, um die Organisation anzugeben",
|
||||
"UidNumber / Uid": "Uidnummer / Uid"
|
||||
},
|
||||
"login": {
|
||||
"Auto sign in": "Auto sign in",
|
||||
"Continue with": "Continue with",
|
||||
"Email or phone": "Email or phone",
|
||||
"Forgot password?": "Forgot password?",
|
||||
"Invalid Email or phone": "Invalid Email or phone",
|
||||
"No account?": "No account?",
|
||||
"Or sign in with another account": "Or sign in with another account",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Please input your code!": "Please input your code!",
|
||||
"Please input your password!": "Please input your password!",
|
||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||
"Sign In": "Sign In",
|
||||
"Sign in with code": "Sign in with code",
|
||||
"Sign in with password": "Sign in with password",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"sign up now": "sign up now",
|
||||
"username, Email or phone": "username, Email or phone"
|
||||
"Auto sign in": "Auto-Anmelden",
|
||||
"Continue with": "Weiter mit",
|
||||
"Email or phone": "E-Mail oder Telefon",
|
||||
"Forgot password?": "Passwort vergessen?",
|
||||
"Invalid Email or phone": "Ungültige E-Mail oder Telefon",
|
||||
"No account?": "Kein Konto?",
|
||||
"Or sign in with another account": "Oder melden Sie sich mit einem anderen Konto an",
|
||||
"Password": "Passwort",
|
||||
"Password - Tooltip": "Passwort - Tooltip",
|
||||
"Please input your code!": "Bitte gib deinen Code ein!",
|
||||
"Please input your password!": "Bitte geben Sie Ihr Passwort ein!",
|
||||
"Please input your password, at least 6 characters!": "Bitte geben Sie Ihr Passwort ein, mindestens 6 Zeichen!",
|
||||
"Please input your username, Email or phone!": "Bitte geben Sie Ihren Benutzernamen, E-Mail oder Telefon ein!",
|
||||
"Sign In": "Anmelden",
|
||||
"Sign in with code": "Mit Code anmelden",
|
||||
"Sign in with password": "Mit Passwort anmelden",
|
||||
"Sign in with {type}": "Mit {type} anmelden",
|
||||
"Signing in...": "Anmelden...",
|
||||
"The input is not valid Email or Phone!": "Die Eingabe ist keine gültige E-Mail oder Telefon!",
|
||||
"To access": "Zu Zugriff",
|
||||
"sign up now": "jetzt anmelden",
|
||||
"username, Email or phone": "Benutzername, E-Mail oder Telefon"
|
||||
},
|
||||
"organization": {
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Favicon": "Favicon",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Website URL": "Website URL",
|
||||
"Default avatar": "Standard Avatar",
|
||||
"Edit Organization": "Organisation bearbeiten",
|
||||
"Favicon": "Févicon",
|
||||
"Soft deletion": "Weiche Löschung",
|
||||
"Soft deletion - Tooltip": "Weiche Löschung - Tooltip",
|
||||
"Website URL": "Website-URL",
|
||||
"Website URL - Tooltip": "Unique string-style identifier"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Aktionen",
|
||||
"Actions - Tooltip": "Aktionen - Tooltip",
|
||||
"Edit Permission": "Berechtigung bearbeiten",
|
||||
"Effect": "Effekt",
|
||||
"Effect - Tooltip": "Effekt - Tooltip",
|
||||
"Resource type": "Ressourcentyp",
|
||||
"Resource type - Tooltip": "Ressourcentyp - Tooltip",
|
||||
"Resources": "Ressourcen"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
"Bucket": "Bucket",
|
||||
"Access key": "Zugangsschlüssel",
|
||||
"Access key - Tooltip": "Zugriffsschlüssel - Tooltip",
|
||||
"Bucket": "Eimer",
|
||||
"Bucket - Tooltip": "Storage bucket name",
|
||||
"Can not parse Metadata": "Can not parse Metadata",
|
||||
"Category": "Category",
|
||||
"Can not parse Metadata": "Metadaten können nicht analysiert werden",
|
||||
"Category": "Kategorie",
|
||||
"Category - Tooltip": "Unique string-style identifier",
|
||||
"Client ID": "Client ID",
|
||||
"Client ID": "Kunden-ID",
|
||||
"Client ID - Tooltip": "Unique string-style identifier",
|
||||
"Client ID 2": "Client ID 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
|
||||
"Client secret": "Client secret",
|
||||
"Client secret": "Kundengeheimnis",
|
||||
"Client secret - Tooltip": "Unique string-style identifier",
|
||||
"Client secret 2": "Client secret 2",
|
||||
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
|
||||
"Copy": "Copy",
|
||||
"Domain": "Domain",
|
||||
"Client secret 2": "Client Secret 2",
|
||||
"Client secret 2 - Tooltip": "Client Secret 2 - Tooltip",
|
||||
"Copy": "Kopieren",
|
||||
"Domain": "Domäne",
|
||||
"Domain - Tooltip": "Storage endpoint custom domain",
|
||||
"Edit Provider": "Edit Provider",
|
||||
"Edit Provider": "Anbieter bearbeiten",
|
||||
"Email Content": "Email Content",
|
||||
"Email Content - Tooltip": "Unique string-style identifier",
|
||||
"Email Title": "Email Title",
|
||||
"Email Title": "E-Mail-Titel",
|
||||
"Email Title - Tooltip": "Unique string-style identifier",
|
||||
"Endpoint": "Endpoint",
|
||||
"Endpoint (Intranet)": "Endpoint (Intranet)",
|
||||
"Endpoint (Intranet)": "Endpunkt (Intranet)",
|
||||
"Host": "Host",
|
||||
"Host - Tooltip": "Unique string-style identifier",
|
||||
"IdP": "IdP",
|
||||
"IdP public key": "IdP public key",
|
||||
"Issuer URL": "Issuer URL",
|
||||
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Metadata": "Metadata",
|
||||
"Metadata - Tooltip": "Metadata - Tooltip",
|
||||
"Method": "Method",
|
||||
"IdP public key": "IdP-öffentlicher Schlüssel",
|
||||
"Issuer URL": "Ausgabe-URL",
|
||||
"Issuer URL - Tooltip": "Ausgabe-URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link erfolgreich in die Zwischenablage kopiert",
|
||||
"Metadata": "Metadaten",
|
||||
"Metadata - Tooltip": "Metadaten - Tooltip",
|
||||
"Method": "Methode",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Parse Metadata successfully": "Metadaten erfolgreich analysieren",
|
||||
"Port": "Port",
|
||||
"Port - Tooltip": "Unique string-style identifier",
|
||||
"Provider URL": "Provider URL",
|
||||
"Provider URL": "Provider-URL",
|
||||
"Provider URL - Tooltip": "Unique string-style identifier",
|
||||
"Region ID": "Region ID",
|
||||
"Region ID - Tooltip": "Region ID - Tooltip",
|
||||
"Region endpoint for Internet": "Region endpoint for Internet",
|
||||
"Region endpoint for Intranet": "Region endpoint for Intranet",
|
||||
"Region endpoint for Internet": "Region Endpunkt für Internet",
|
||||
"Region endpoint for Intranet": "Region Endpunkt für Intranet",
|
||||
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL": "SP-ACS-URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"Secret access key": "Secret access key",
|
||||
"Secret access key": "Geheimer Zugangsschlüssel",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
|
||||
"Sign Name": "Sign Name",
|
||||
"Sign Name": "Schild Name",
|
||||
"Sign Name - Tooltip": "Unique string-style identifier",
|
||||
"Sign request": "Sign request",
|
||||
"Sign request - Tooltip": "Sign request - Tooltip",
|
||||
"Signin HTML": "Signin HTML",
|
||||
"Signin HTML - Edit": "Signin HTML - Edit",
|
||||
"Sign request": "Signaturanfrage",
|
||||
"Sign request - Tooltip": "Signaturanfrage - Tooltip",
|
||||
"Signin HTML": "HTML anmelden",
|
||||
"Signin HTML - Edit": "Anmeldung HTML - Bearbeiten",
|
||||
"Signin HTML - Tooltip": "Signin HTML - Tooltip",
|
||||
"Signup HTML": "Signup HTML",
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Signup HTML - Tooltip",
|
||||
"Template Code": "Template Code",
|
||||
"Signup HTML": "HTML registrieren",
|
||||
"Signup HTML - Edit": "HTML registrieren - Bearbeiten",
|
||||
"Signup HTML - Tooltip": "HTML registrieren - Tooltip",
|
||||
"Template Code": "Vorlagencode",
|
||||
"Template Code - Tooltip": "Unique string-style identifier",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"Terms of Use - Tooltip": "Terms of Use - Tooltip",
|
||||
"Type": "Type",
|
||||
"Terms of Use": "Nutzungsbedingungen",
|
||||
"Terms of Use - Tooltip": "Nutzungsbedingungen - Tooltip",
|
||||
"Type": "Typ",
|
||||
"Type - Tooltip": "Unique string-style identifier",
|
||||
"alertType": "alertType",
|
||||
"alertType": "alarmtyp",
|
||||
"canSignIn": "canSignIn",
|
||||
"canSignUp": "canSignUp",
|
||||
"canUnlink": "canUnlink",
|
||||
"prompted": "prompted",
|
||||
"required": "required",
|
||||
"rule": "rule",
|
||||
"visible": "visible"
|
||||
"prompted": "gefragt",
|
||||
"required": "benötigt",
|
||||
"rule": "regel",
|
||||
"visible": "sichtbar"
|
||||
},
|
||||
"record": {
|
||||
"Is Triggered": "Is Triggered"
|
||||
"Is Triggered": "Wird ausgelöst"
|
||||
},
|
||||
"resource": {
|
||||
"Application": "Application",
|
||||
"Copy Link": "Copy Link",
|
||||
"File name": "File name",
|
||||
"File size": "File size",
|
||||
"Application": "Anwendung",
|
||||
"Copy Link": "Link kopieren",
|
||||
"File name": "Dateiname",
|
||||
"File size": "Größe der Datei",
|
||||
"Format": "Format",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Parent": "Parent",
|
||||
"Tag": "Tag",
|
||||
"Type": "Type",
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
"Link copied to clipboard successfully": "Link erfolgreich in die Zwischenablage kopiert",
|
||||
"Parent": "Elternteil",
|
||||
"Tag": "Markierung",
|
||||
"Type": "Typ",
|
||||
"Upload a file...": "Datei hochladen...",
|
||||
"User": "Benutzer"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Rolle bearbeiten",
|
||||
"Sub roles": "Unterrollen",
|
||||
"Sub roles - Tooltip": "Unterrollen - Tooltip",
|
||||
"Sub users": "Unternutzer",
|
||||
"Sub users - Tooltip": "Unterbenutzer - Tooltip"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
"Decline": "Decline",
|
||||
"Have account?": "Have account?",
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
"The input is not valid Phone!": "The input is not valid Phone!",
|
||||
"Unknown Check Type": "Unknown Check Type",
|
||||
"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"
|
||||
"Accept": "Akzeptieren",
|
||||
"Confirm": "Bestätigen",
|
||||
"Decline": "Ablehnen",
|
||||
"Have account?": "Haben Sie Konto?",
|
||||
"Please accept the agreement!": "Bitte akzeptieren Sie die Vereinbarung!",
|
||||
"Please click the below button to sign in": "Bitte klicken Sie auf die Schaltfläche unten, 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 ID Kartennummer ein!",
|
||||
"Please input your Email!": "Bitte geben Sie Ihre E-Mail ein!",
|
||||
"Please input your ID card number!": "Bitte geben Sie Ihre ID Kartennummer ein!",
|
||||
"Please input your address!": "Bitte geben Sie Ihre Adresse ein!",
|
||||
"Please input your affiliation!": "Bitte geben Sie Ihre Zugehörigkeit ein!",
|
||||
"Please input your display name!": "Bitte geben Sie Ihren Anzeigenamen ein!",
|
||||
"Please input your personal name!": "Bitte geben Sie Ihren persönlichen Namen ein!",
|
||||
"Please input your phone number!": "Bitte geben Sie Ihre Telefonnummer ein!",
|
||||
"Please select your country/region!": "Bitte wählen Sie Ihr Land/Ihre Region!",
|
||||
"Terms of Use": "Nutzungsbedingungen",
|
||||
"The input is not valid Email!": "Die Eingabe ist ungültig!",
|
||||
"The input is not valid Phone!": "Die Eingabe ist nicht gültig!",
|
||||
"Unknown Check Type": "Unbekannter Schecktyp",
|
||||
"Username": "Benutzername",
|
||||
"Username - Tooltip": "Benutzername - Tooltip",
|
||||
"Your account has been created!": "Ihr Konto wurde erstellt!",
|
||||
"Your confirmed password is inconsistent with the password!": "Ihr bestätigtes Passwort stimmt nicht mit dem Passwort überein!",
|
||||
"sign in now": "jetzt anmelden"
|
||||
},
|
||||
"syncer": {
|
||||
"Affiliation table": "Affiliation table",
|
||||
"Affiliation table - Tooltip": "Affiliation table - Tooltip",
|
||||
"Avatar base URL": "Avatar base URL",
|
||||
"Avatar base URL - Tooltip": "Avatar base URL - Tooltip",
|
||||
"Casdoor column": "Casdoor column",
|
||||
"Column name": "Column name",
|
||||
"Column type": "Column type",
|
||||
"Database": "Database",
|
||||
"Database - Tooltip": "Database - Tooltip",
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
"Table - Tooltip": "Table - Tooltip",
|
||||
"Table columns": "Table columns",
|
||||
"Table columns - Tooltip": "Table columns - Tooltip",
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
"Affiliation table": "Affiliationstabelle",
|
||||
"Affiliation table - Tooltip": "Affiliationstabelle - Tooltip",
|
||||
"Avatar base URL": "Avatar Basis-URL",
|
||||
"Avatar base URL - Tooltip": "Avatar Basis-URL - Tooltip",
|
||||
"Casdoor column": "Casdoorsäule",
|
||||
"Column name": "Spaltenname",
|
||||
"Column type": "Spaltentyp",
|
||||
"Database": "Datenbank",
|
||||
"Database - Tooltip": "Datenbank - Tooltip",
|
||||
"Database type": "Datenbanktyp",
|
||||
"Database type - Tooltip": "Datenbanktyp - Tooltip",
|
||||
"Edit Syncer": "Syncer bearbeiten",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Ist gehasht",
|
||||
"Sync interval": "Sync-Intervall",
|
||||
"Sync interval - Tooltip": "Sync-Intervall - Tooltip",
|
||||
"Table": "Tisch",
|
||||
"Table - Tooltip": "Tisch - Tooltip",
|
||||
"Table columns": "Tabellenspalten",
|
||||
"Table columns - Tooltip": "Tabellenspalten - Tooltip",
|
||||
"Table primary key": "Primärschlüssel der Tabelle",
|
||||
"Table primary key - Tooltip": "Primärschlüssel der Tabelle - Tooltip"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
"Access token": "Zugangs-Token",
|
||||
"Authorization code": "Autorisierungscode",
|
||||
"Edit Token": "Token bearbeiten",
|
||||
"Expires in": "Läuft ab",
|
||||
"Scope": "Bereich",
|
||||
"Token type": "Token-Typ"
|
||||
},
|
||||
"user": {
|
||||
"\" + destType + \" reset": "\" + destType + \" reset",
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"\" + destType + \" reset": "\" + destType + \" Reset",
|
||||
"3rd-party logins": "3rd-Party-Logins",
|
||||
"3rd-party logins - Tooltip": "Use third-party apps to log in",
|
||||
"Address": "Address",
|
||||
"Address": "Adresse",
|
||||
"Address - Tooltip": "Unique string-style identifier",
|
||||
"Affiliation": "Affiliation",
|
||||
"Affiliation": "Zugehörigkeit",
|
||||
"Affiliation - Tooltip": "Unique string-style identifier",
|
||||
"Bio": "Bio",
|
||||
"Bio - Tooltip": "Bio - Tooltip",
|
||||
"Cancel": "Cancel",
|
||||
"Code Sent": "Code Sent",
|
||||
"Country/Region": "Country/Region",
|
||||
"Cancel": "Abbrechen",
|
||||
"Code Sent": "Code gesendet",
|
||||
"Country/Region": "Land/Region",
|
||||
"Country/Region - Tooltip": "Country/Region",
|
||||
"Edit User": "Edit User",
|
||||
"Edit User": "Benutzer bearbeiten",
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
"Homepage - Tooltip": "Startseite - Tooltip",
|
||||
"ID card": "Personalausweis",
|
||||
"Input your email": "E-Mail eingeben",
|
||||
"Input your phone number": "Telefonnummer eingeben",
|
||||
"Is admin": "Ist Admin",
|
||||
"Is admin - Tooltip": "Is the application administrator",
|
||||
"Is deleted": "Is deleted",
|
||||
"Is deleted - Tooltip": "Is deleted - Tooltip",
|
||||
"Is forbidden": "Is forbidden",
|
||||
"Is deleted": "Ist gelöscht",
|
||||
"Is deleted - Tooltip": "Ist gelöscht - Tooltip",
|
||||
"Is forbidden": "Ist verboten",
|
||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||
"Is global admin": "Is global admin",
|
||||
"Is global admin": "Ist globaler Admin",
|
||||
"Is global admin - Tooltip": "Is the application global administrator",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New phone": "New phone",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
"Password": "Password",
|
||||
"Password Set": "Password Set",
|
||||
"Properties": "Properties",
|
||||
"Re-enter New": "Re-enter New",
|
||||
"Location": "Standort",
|
||||
"Location - Tooltip": "Standort - Tooltip",
|
||||
"Modify password...": "Passwort ändern...",
|
||||
"New Email": "Neue E-Mail",
|
||||
"New Password": "Neues Passwort",
|
||||
"New phone": "Neues Telefon",
|
||||
"OK": "Ok",
|
||||
"Old Password": "Altes Passwort",
|
||||
"Password": "Passwort",
|
||||
"Password Set": "Passwort setzen",
|
||||
"Properties": "Eigenschaften",
|
||||
"Re-enter New": "Neu erneut eingeben",
|
||||
"Reset Email...": "Reset Email...",
|
||||
"Reset Phone...": "Reset Phone...",
|
||||
"Select a photo...": "Select a photo...",
|
||||
"Set Password": "Set Password",
|
||||
"Set new profile picture": "Set new profile picture",
|
||||
"Set password...": "Set password...",
|
||||
"Tag": "Tag",
|
||||
"Reset Phone...": "Telefon zurücksetzen...",
|
||||
"Select a photo...": "Wählen Sie ein Foto...",
|
||||
"Set Password": "Passwort festlegen",
|
||||
"Set new profile picture": "Neues Profilbild festlegen",
|
||||
"Set password...": "Passwort festlegen...",
|
||||
"Tag": "Markierung",
|
||||
"Tag - Tooltip": "Unique string-style identifier",
|
||||
"Title": "Title",
|
||||
"Title": "Titel",
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
"Two passwords you typed do not match.": "Zwei eingegebene Passwörter stimmen nicht überein.",
|
||||
"Unlink": "Link aufheben",
|
||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||
"Upload a photo": "Foto hochladen",
|
||||
"input password": "Passwort eingeben"
|
||||
},
|
||||
"webhook": {
|
||||
"Content type": "Content type",
|
||||
"Content type - Tooltip": "Content type - Tooltip",
|
||||
"Edit Webhook": "Edit Webhook",
|
||||
"Events": "Events",
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Content type": "Inhaltstyp",
|
||||
"Content type - Tooltip": "Inhaltstyp - Tooltip",
|
||||
"Edit Webhook": "Webhook bearbeiten",
|
||||
"Events": "Ereignisse",
|
||||
"Events - Tooltip": "Ereignisse - Tooltip",
|
||||
"Headers": "Kopfzeilen",
|
||||
"Headers - Tooltip": "Kopfzeilen - Tooltip",
|
||||
"Is user extended": "Ist Benutzer erweitert",
|
||||
"Is user extended - Tooltip": "Ist Benutzer erweitert - Tooltip",
|
||||
"Method": "Methode",
|
||||
"Method - Tooltip": "Methode - Tooltip",
|
||||
"Name": "Name",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
"Value": "Wert"
|
||||
}
|
||||
}
|
@ -33,6 +33,29 @@
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bit size",
|
||||
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||
"Copy private key": "Copy private key",
|
||||
"Copy public key": "Copy public key",
|
||||
"Crypto algorithm": "Crypto algorithm",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "Download private key",
|
||||
"Download public key": "Download public key",
|
||||
"Edit Cert": "Edit Cert",
|
||||
"Expire in years": "Expire in years",
|
||||
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||
"Public key": "Public key",
|
||||
"Public key - Tooltip": "Public key - Tooltip",
|
||||
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||
"Scope": "Scope",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
@ -69,6 +92,7 @@
|
||||
"Avatar - Tooltip": "Avatar - Tooltip",
|
||||
"Back Home": "Back Home",
|
||||
"Captcha": "Captcha",
|
||||
"Certs": "Certs",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
@ -109,6 +133,7 @@
|
||||
"Password salt - Tooltip": "Password salt - Tooltip",
|
||||
"Password type": "Password type",
|
||||
"Password type - Tooltip": "Password type - Tooltip",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone - Tooltip",
|
||||
@ -122,12 +147,15 @@
|
||||
"Records": "Records",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Roles": "Roles",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Signin URL - Tooltip": "Signin URL - Tooltip",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL - Tooltip": "Signup URL - Tooltip",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -206,6 +234,16 @@
|
||||
"Website URL": "Website URL",
|
||||
"Website URL - Tooltip": "Website URL - Tooltip"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
@ -301,6 +339,13 @@
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
"Sub users - Tooltip": "Sub users - Tooltip"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
@ -309,7 +354,9 @@
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input the correct ID card number!": "Please input the correct ID card number!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your ID card number!": "Please input your ID card number!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
@ -339,6 +386,8 @@
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
@ -375,6 +424,7 @@
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"ID card": "ID card",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
@ -410,6 +460,7 @@
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
},
|
||||
@ -421,6 +472,8 @@
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Is user extended": "Is user extended",
|
||||
"Is user extended - Tooltip": "Is user extended - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
|
@ -1,431 +1,484 @@
|
||||
{
|
||||
"account": {
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"My Account": "My Account",
|
||||
"Settings for your account": "Settings for your account",
|
||||
"Sign Up": "Sign Up"
|
||||
"Login": "Se connecter",
|
||||
"Logout": "Déconnexion",
|
||||
"My Account": "Mon Compte",
|
||||
"Settings for your account": "Paramètres de votre compte",
|
||||
"Sign Up": "S'inscrire"
|
||||
},
|
||||
"application": {
|
||||
"Edit Application": "Edit Application",
|
||||
"Enable code signin": "Enable code signin",
|
||||
"Enable code signin - Tooltip": "Enable code signin - Tooltip",
|
||||
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
|
||||
"Enable signup": "Enable signup",
|
||||
"Edit Application": "Modifier l'application",
|
||||
"Enable code signin": "Activer la connexion au code",
|
||||
"Enable code signin - Tooltip": "Activer la connexion au code - infobulle",
|
||||
"Enable signin session - Tooltip": "Activer la session de connexion - infobulle",
|
||||
"Enable signup": "Activer l'inscription",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Password ON": "Password ON",
|
||||
"File uploaded successfully": "Fichier téléchargé avec succès",
|
||||
"Password ON": "Mot de passe activé",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Redirect URL": "Redirect URL",
|
||||
"Redirect URLs": "Redirect URLs",
|
||||
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
|
||||
"Redirect URL": "URL de redirection",
|
||||
"Redirect URLs": "URL de redirection",
|
||||
"Redirect URLs - Tooltip": "List of redirect addresses after successful login",
|
||||
"Refresh token expire": "Refresh token expire",
|
||||
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Refresh token expire": "Expiration du jeton d'actualisation",
|
||||
"Refresh token expire - Tooltip": "Expiration du jeton d'actualisation - infobulle",
|
||||
"Signin session": "Connexion à la session",
|
||||
"Signup items": "Inscrire des éléments",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Test prompt page..": "Test prompt page..",
|
||||
"Test signin page..": "Test signin page..",
|
||||
"Test signup page..": "Test signup page..",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Test prompt page..": "Tester la vitesse d'exécution.",
|
||||
"Test signin page..": "Tester la connexion en ligne.",
|
||||
"Test signup page..": "Tester l'inscription.",
|
||||
"Token expire": "Expiration du jeton",
|
||||
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
|
||||
"Token format": "Format du jeton",
|
||||
"Token format - Tooltip": "Format du jeton - infobulle"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Taille du bit",
|
||||
"Bit size - Tooltip": "Taille du bit - Infobulle",
|
||||
"Copy private key": "Copier la clé privée",
|
||||
"Copy public key": "Copier la clé publique",
|
||||
"Crypto algorithm": "Algorithme de cryptomonnaie",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "Télécharger la clé privée",
|
||||
"Download public key": "Télécharger la clé publique",
|
||||
"Edit Cert": "Modifier le certificat",
|
||||
"Expire in years": "Expire dans les années",
|
||||
"Expire in years - Tooltip": "Expire dans les années - infobulle",
|
||||
"Private key": "Clé privée",
|
||||
"Private key - Tooltip": "Clé privée - Infobulle",
|
||||
"Private key copied to clipboard successfully": "Clé privée copiée dans le presse-papiers avec succès",
|
||||
"Public key": "Clé publique",
|
||||
"Public key - Tooltip": "Clé publique - Infobulle",
|
||||
"Public key copied to clipboard successfully": "Clé publique copiée dans le presse-papiers avec succès",
|
||||
"Scope": "Périmètre d'application",
|
||||
"Scope - Tooltip": "Scope - Infobulle",
|
||||
"Type": "Type de texte",
|
||||
"Type - Tooltip": "Type - Infobulle"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
"Empty Code": "Empty Code",
|
||||
"Enter your code": "Enter your code",
|
||||
"Phone code": "Phone code",
|
||||
"Please input your phone verification code!": "Please input your phone verification code!",
|
||||
"Please input your verification code!": "Please input your verification code!",
|
||||
"Send Code": "Send Code",
|
||||
"Sending Code": "Sending Code",
|
||||
"Submit and complete": "Submit and complete"
|
||||
"Code You Received": "Code que vous avez reçu",
|
||||
"Email code": "Code de l'e-mail",
|
||||
"Empty Code": "Code vide",
|
||||
"Enter your code": "Entrez votre code",
|
||||
"Phone code": "Code du téléphone",
|
||||
"Please input your phone verification code!": "Veuillez entrer le code de vérification de votre téléphone !",
|
||||
"Please input your verification code!": "Veuillez entrer votre code de vérification !",
|
||||
"Send Code": "Envoyer le code",
|
||||
"Sending Code": "Code d'envoi",
|
||||
"Submit and complete": "Soumettre et compléter"
|
||||
},
|
||||
"forget": {
|
||||
"Account": "Account",
|
||||
"Change Password": "Change Password",
|
||||
"Choose email or phone": "Choose email or phone",
|
||||
"Confirm": "Confirm",
|
||||
"Next Step": "Next Step",
|
||||
"Password": "Password",
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Account": "Compte client",
|
||||
"Change Password": "Changer le mot de passe",
|
||||
"Choose email or phone": "Choisissez un e-mail ou un téléphone",
|
||||
"Confirm": "Valider",
|
||||
"Next Step": "Étape suivante",
|
||||
"Password": "Mot de passe",
|
||||
"Please input your username!": "Veuillez entrer votre nom d'utilisateur !",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Verify": "Verify"
|
||||
"Retrieve password": "Récupérer le mot de passe",
|
||||
"Verify": "Vérifier"
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Add": "Ajouter",
|
||||
"Affiliation URL": "URL d'affiliation",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
"Application": "Application",
|
||||
"Applications": "Applications",
|
||||
"Applications that require authentication": "Applications that require authentication",
|
||||
"Avatar": "Avatar",
|
||||
"Applications that require authentication": "Applications nécessitant une authentification",
|
||||
"Avatar": "Avatars",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Back Home": "Retour à la page d'accueil",
|
||||
"Captcha": "Captcha",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
"Certs": "Certes",
|
||||
"Client IP": "IP du client",
|
||||
"Created time": "Date de création",
|
||||
"Default avatar": "Avatar par défaut",
|
||||
"Default avatar - Tooltip": "default avatar",
|
||||
"Delete": "Delete",
|
||||
"Description": "Description",
|
||||
"Delete": "Supprimez",
|
||||
"Description": "Libellé",
|
||||
"Description - Tooltip": "Related descriptive information",
|
||||
"Display name": "Display name",
|
||||
"Display name": "Nom affiché",
|
||||
"Display name - Tooltip": "Name shown to users, repeatable",
|
||||
"Down": "Down",
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Down": "Bas",
|
||||
"Edit": "Editer",
|
||||
"Email": "Courriel",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL": "Oublier l'URL",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Home",
|
||||
"Home": "Domicile",
|
||||
"Home - Tooltip": "Application homepage",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "random string",
|
||||
"Is enabled": "Is enabled",
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"Is enabled": "Est activé",
|
||||
"Is enabled - Tooltip": "Est activé - infobulle",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"LDAPs - Tooltip": "LDAPs - Infobulle",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Method": "Method",
|
||||
"Name": "Name",
|
||||
"Master password": "Mot de passe maître",
|
||||
"Master password - Tooltip": "Mot de passe maître - Infobulle",
|
||||
"Method": "Méthode",
|
||||
"Name": "Nom",
|
||||
"Name - Tooltip": "Unique string-style identifier",
|
||||
"OAuth providers": "OAuth providers",
|
||||
"Organization": "Organization",
|
||||
"OAuth providers": "Fournisseurs OAuth",
|
||||
"Organization": "Organisation",
|
||||
"Organization - Tooltip": "The group the user belongs to",
|
||||
"Organizations": "Organizations",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Organizations": "Organisations",
|
||||
"Password": "Mot de passe",
|
||||
"Password - Tooltip": "Mot de passe - Info-bulle",
|
||||
"Password salt": "Sel de mot de passe",
|
||||
"Password salt - Tooltip": "Random parameters used for password encryption",
|
||||
"Password type": "Password type",
|
||||
"Password type": "Type de mot de passe",
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Nom personnel",
|
||||
"Phone": "Téléphone",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix": "Préfixe du téléphone",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Preview",
|
||||
"Preview": "Aperçu",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Provider": "Provider",
|
||||
"Providers": "Providers",
|
||||
"Provider": "Fournisseur",
|
||||
"Providers": "Fournisseurs",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Records": "Records",
|
||||
"Records": "Enregistrements",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Resources": "Ressource",
|
||||
"Roles": "Rôles",
|
||||
"Save": "Enregistrer",
|
||||
"Save & Exit": "Enregistrer & Quitter",
|
||||
"Signin URL": "URL de connexion",
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL": "URL d'inscription",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Syncers": "Synchronisateurs",
|
||||
"Timestamp": "Horodatage",
|
||||
"Tokens": "Jetons",
|
||||
"URL": "URL",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
"User containers": "User containers",
|
||||
"User type": "User type",
|
||||
"Up": "Monter",
|
||||
"User": "Utilisateur",
|
||||
"User - Tooltip": "Utilisateur - infobulle",
|
||||
"User containers": "Conteneurs utilisateur",
|
||||
"User type": "Type d'utilisateur",
|
||||
"User type - Tooltip": "Permission role owned by the user",
|
||||
"Users": "Users",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Users": "Utilisateurs",
|
||||
"Users under all organizations": "Utilisateurs sous toutes les organisations",
|
||||
"Webhooks": "Webhooks",
|
||||
"{total} in total": "{total} in total"
|
||||
"{total} in total": "{total} au total"
|
||||
},
|
||||
"ldap": {
|
||||
"Address": "Address",
|
||||
"Admin": "Admin",
|
||||
"Address": "Adresses",
|
||||
"Admin": "Administrateur",
|
||||
"Admin - Tooltip": "LDAP server admin CN or ID",
|
||||
"Admin Password": "Admin Password",
|
||||
"Admin Password": "Mot de passe admin",
|
||||
"Admin Password - Tooltip": "LDAP server admin password",
|
||||
"Auto Sync": "Auto Sync",
|
||||
"Auto Sync": "Synchronisation automatique",
|
||||
"Auto Sync - Tooltip": "Auto sync config, disable if is 0",
|
||||
"Base DN": "Base DN",
|
||||
"Base DN": "DN de base",
|
||||
"Base DN - Tooltip": "LDAP search base DN",
|
||||
"CN": "CN",
|
||||
"Edit LDAP": "Edit LDAP",
|
||||
"Email": "Email",
|
||||
"Group Id": "Group Id",
|
||||
"Edit LDAP": "Modifier LDAP",
|
||||
"Email": "Courriel",
|
||||
"Group Id": "Identifiant du groupe",
|
||||
"ID": "ID",
|
||||
"Last Sync": "Last Sync",
|
||||
"Phone": "Phone",
|
||||
"Server": "Server",
|
||||
"Server Host": "Server Host",
|
||||
"Last Sync": "Dernière synchronisation",
|
||||
"Phone": "Téléphone",
|
||||
"Server": "Serveur",
|
||||
"Server Host": "Hôte du serveur",
|
||||
"Server Host - Tooltip": "LDAP server host",
|
||||
"Server Name": "Server Name",
|
||||
"Server Name": "Nom du serveur",
|
||||
"Server Name - Tooltip": "LDAP server config display name",
|
||||
"Server Port": "Server Port",
|
||||
"Server Port": "Port du serveur",
|
||||
"Server Port - Tooltip": "LDAP server port",
|
||||
"Sync": "Sync",
|
||||
"The Auto Sync option will sync all users to specify organization": "The Auto Sync option will sync all users to specify organization",
|
||||
"UidNumber / Uid": "UidNumber / Uid"
|
||||
"Sync": "Synchroniser",
|
||||
"The Auto Sync option will sync all users to specify organization": "L'option de synchronisation automatique synchronisera tous les utilisateurs pour spécifier l'organisation",
|
||||
"UidNumber / Uid": "Numéro Uid/Uid"
|
||||
},
|
||||
"login": {
|
||||
"Auto sign in": "Auto sign in",
|
||||
"Continue with": "Continue with",
|
||||
"Email or phone": "Email or phone",
|
||||
"Forgot password?": "Forgot password?",
|
||||
"Invalid Email or phone": "Invalid Email or phone",
|
||||
"No account?": "No account?",
|
||||
"Or sign in with another account": "Or sign in with another account",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Please input your code!": "Please input your code!",
|
||||
"Please input your password!": "Please input your password!",
|
||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||
"Sign In": "Sign In",
|
||||
"Sign in with code": "Sign in with code",
|
||||
"Sign in with password": "Sign in with password",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"sign up now": "sign up now",
|
||||
"username, Email or phone": "username, Email or phone"
|
||||
"Auto sign in": "Connexion automatique",
|
||||
"Continue with": "Continuer avec",
|
||||
"Email or phone": "Courriel ou téléphone",
|
||||
"Forgot password?": "Mot de passe oublié ?",
|
||||
"Invalid Email or phone": "E-mail ou téléphone invalide",
|
||||
"No account?": "Pas de compte ?",
|
||||
"Or sign in with another account": "Ou connectez-vous avec un autre compte",
|
||||
"Password": "Mot de passe",
|
||||
"Password - Tooltip": "Mot de passe - Info-bulle",
|
||||
"Please input your code!": "Veuillez saisir votre code !",
|
||||
"Please input your password!": "Veuillez saisir votre mot de passe !",
|
||||
"Please input your password, at least 6 characters!": "Veuillez entrer votre mot de passe, au moins 6 caractères !",
|
||||
"Please input your username, Email or phone!": "Veuillez entrer votre nom d'utilisateur, votre e-mail ou votre téléphone!",
|
||||
"Sign In": "Se connecter",
|
||||
"Sign in with code": "Se connecter avec le code",
|
||||
"Sign in with password": "Se connecter avec le mot de passe",
|
||||
"Sign in with {type}": "Se connecter avec {type}",
|
||||
"Signing in...": "Connexion en cours...",
|
||||
"The input is not valid Email or Phone!": "L'entrée n'est pas valide Email ou Téléphone !",
|
||||
"To access": "Pour accéder à",
|
||||
"sign up now": "inscrivez-vous maintenant",
|
||||
"username, Email or phone": "nom d'utilisateur, e-mail ou téléphone"
|
||||
},
|
||||
"organization": {
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Default avatar": "Avatar par défaut",
|
||||
"Edit Organization": "Modifier l'organisation",
|
||||
"Favicon": "Favicon",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Website URL": "Website URL",
|
||||
"Soft deletion": "Suppression du logiciel",
|
||||
"Soft deletion - Tooltip": "Suppression de soft - infobulle",
|
||||
"Website URL": "URL du site web",
|
||||
"Website URL - Tooltip": "Unique string-style identifier"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Info-bulle",
|
||||
"Edit Permission": "Autorisation d'édition",
|
||||
"Effect": "Effet",
|
||||
"Effect - Tooltip": "Effet - Infobulle",
|
||||
"Resource type": "Type de ressource",
|
||||
"Resource type - Tooltip": "Type de ressource - infobulle",
|
||||
"Resources": "Ressource"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
"Bucket": "Bucket",
|
||||
"Access key": "Clé d'accès",
|
||||
"Access key - Tooltip": "Touche d'accès - Infobulle",
|
||||
"Bucket": "Seau",
|
||||
"Bucket - Tooltip": "Storage bucket name",
|
||||
"Can not parse Metadata": "Can not parse Metadata",
|
||||
"Category": "Category",
|
||||
"Can not parse Metadata": "Impossible d'analyser les métadonnées",
|
||||
"Category": "Catégorie",
|
||||
"Category - Tooltip": "Unique string-style identifier",
|
||||
"Client ID": "Client ID",
|
||||
"Client ID": "ID du client",
|
||||
"Client ID - Tooltip": "Unique string-style identifier",
|
||||
"Client ID 2": "Client ID 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
|
||||
"Client secret": "Client secret",
|
||||
"Client ID 2": "ID client 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - infobulle",
|
||||
"Client secret": "Secret du client",
|
||||
"Client secret - Tooltip": "Unique string-style identifier",
|
||||
"Client secret 2": "Client secret 2",
|
||||
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
|
||||
"Copy": "Copy",
|
||||
"Domain": "Domain",
|
||||
"Client secret 2 - Tooltip": "Secret client 2 - Infobulle",
|
||||
"Copy": "Copie",
|
||||
"Domain": "Domaine",
|
||||
"Domain - Tooltip": "Storage endpoint custom domain",
|
||||
"Edit Provider": "Edit Provider",
|
||||
"Edit Provider": "Modifier le fournisseur",
|
||||
"Email Content": "Email Content",
|
||||
"Email Content - Tooltip": "Unique string-style identifier",
|
||||
"Email Title": "Email Title",
|
||||
"Email Title": "Titre de l'e-mail",
|
||||
"Email Title - Tooltip": "Unique string-style identifier",
|
||||
"Endpoint": "Endpoint",
|
||||
"Endpoint (Intranet)": "Endpoint (Intranet)",
|
||||
"Host": "Host",
|
||||
"Endpoint (Intranet)": "Point de terminaison (Intranet)",
|
||||
"Host": "Hôte",
|
||||
"Host - Tooltip": "Unique string-style identifier",
|
||||
"IdP": "IdP",
|
||||
"IdP public key": "IdP public key",
|
||||
"Issuer URL": "Issuer URL",
|
||||
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Metadata": "Metadata",
|
||||
"Metadata - Tooltip": "Metadata - Tooltip",
|
||||
"Method": "Method",
|
||||
"IdP": "IDP",
|
||||
"IdP public key": "Clé publique IdP",
|
||||
"Issuer URL": "URL de l'émetteur",
|
||||
"Issuer URL - Tooltip": "URL de l'émetteur - infobulle",
|
||||
"Link copied to clipboard successfully": "Lien copié dans le presse-papiers avec succès",
|
||||
"Metadata": "Métadonnées",
|
||||
"Metadata - Tooltip": "Métadonnées - Infobulle",
|
||||
"Method": "Méthode",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"Name": "Nom",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Parse Metadata successfully": "Analyse des métadonnées réussie",
|
||||
"Port": "Port",
|
||||
"Port - Tooltip": "Unique string-style identifier",
|
||||
"Provider URL": "Provider URL",
|
||||
"Provider URL": "URL du fournisseur",
|
||||
"Provider URL - Tooltip": "Unique string-style identifier",
|
||||
"Region ID": "Region ID",
|
||||
"Region ID - Tooltip": "Region ID - Tooltip",
|
||||
"Region endpoint for Internet": "Region endpoint for Internet",
|
||||
"Region endpoint for Intranet": "Region endpoint for Intranet",
|
||||
"Region ID": "ID de la région",
|
||||
"Region ID - Tooltip": "ID de région - infobulle",
|
||||
"Region endpoint for Internet": "Point de terminaison de la région pour Internet",
|
||||
"Region endpoint for Intranet": "Point de terminaison de la région pour Intranet",
|
||||
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"Secret access key": "Secret access key",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
|
||||
"Sign Name": "Sign Name",
|
||||
"SP ACS URL": "URL du SP ACS",
|
||||
"SP ACS URL - Tooltip": "URL SP ACS - infobulle",
|
||||
"SP Entity ID": "ID de l'entité SP",
|
||||
"Secret access key": "Clé d'accès secrète",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Infobulle",
|
||||
"Sign Name": "Nom du panneau",
|
||||
"Sign Name - Tooltip": "Unique string-style identifier",
|
||||
"Sign request": "Sign request",
|
||||
"Sign request - Tooltip": "Sign request - Tooltip",
|
||||
"Signin HTML": "Signin HTML",
|
||||
"Signin HTML - Edit": "Signin HTML - Edit",
|
||||
"Sign request": "Demande de signature",
|
||||
"Sign request - Tooltip": "Demande de signe - infobulle",
|
||||
"Signin HTML": "Connexion HTML",
|
||||
"Signin HTML - Edit": "Connexion HTML - Modifier",
|
||||
"Signin HTML - Tooltip": "Signin HTML - Tooltip",
|
||||
"Signup HTML": "Signup HTML",
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Signup HTML - Tooltip",
|
||||
"Template Code": "Template Code",
|
||||
"Signup HTML": "Inscription HTML",
|
||||
"Signup HTML - Edit": "Inscription HTML - Modifier",
|
||||
"Signup HTML - Tooltip": "Inscription HTML - infobulle",
|
||||
"Template Code": "Code du modèle",
|
||||
"Template Code - Tooltip": "Unique string-style identifier",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"Terms of Use - Tooltip": "Terms of Use - Tooltip",
|
||||
"Type": "Type",
|
||||
"Terms of Use": "Conditions d'utilisation",
|
||||
"Terms of Use - Tooltip": "Conditions d'utilisation - Info-bulle",
|
||||
"Type": "Type de texte",
|
||||
"Type - Tooltip": "Unique string-style identifier",
|
||||
"alertType": "alertType",
|
||||
"alertType": "Type d'alerte",
|
||||
"canSignIn": "canSignIn",
|
||||
"canSignUp": "canSignUp",
|
||||
"canUnlink": "canUnlink",
|
||||
"prompted": "prompted",
|
||||
"required": "required",
|
||||
"rule": "rule",
|
||||
"visible": "visible"
|
||||
"prompted": "invitée",
|
||||
"required": "Obligatoire",
|
||||
"rule": "règle",
|
||||
"visible": "Visible"
|
||||
},
|
||||
"record": {
|
||||
"Is Triggered": "Is Triggered"
|
||||
"Is Triggered": "Est déclenché"
|
||||
},
|
||||
"resource": {
|
||||
"Application": "Application",
|
||||
"Copy Link": "Copy Link",
|
||||
"File name": "File name",
|
||||
"File size": "File size",
|
||||
"Format": "Format",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Copy Link": "Copier le lien",
|
||||
"File name": "Nom du fichier",
|
||||
"File size": "Taille du fichier",
|
||||
"Format": "Formater",
|
||||
"Link copied to clipboard successfully": "Lien copié dans le presse-papiers avec succès",
|
||||
"Parent": "Parent",
|
||||
"Tag": "Tag",
|
||||
"Type": "Type",
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
"Tag": "Étiquette",
|
||||
"Type": "Type de texte",
|
||||
"Upload a file...": "Télécharger un fichier...",
|
||||
"User": "Utilisateur"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Modifier le rôle",
|
||||
"Sub roles": "Sous-rôles",
|
||||
"Sub roles - Tooltip": "Sous-rôles - infobulle",
|
||||
"Sub users": "Sous-utilisateurs",
|
||||
"Sub users - Tooltip": "Sous-utilisateurs - infobulle"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
"Decline": "Decline",
|
||||
"Have account?": "Have account?",
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
"The input is not valid Phone!": "The input is not valid Phone!",
|
||||
"Unknown Check Type": "Unknown Check Type",
|
||||
"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"
|
||||
"Accept": "Accepter",
|
||||
"Confirm": "Valider",
|
||||
"Decline": "Refuser",
|
||||
"Have account?": "Vous avez un compte ?",
|
||||
"Please accept the agreement!": "Veuillez accepter l'accord!",
|
||||
"Please click the below button to sign in": "Veuillez cliquer sur le bouton ci-dessous pour vous connecter",
|
||||
"Please confirm your password!": "Veuillez confirmer votre mot de passe !",
|
||||
"Please input the correct ID card number!": "Veuillez entrer le bon numéro de carte d'identité !",
|
||||
"Please input your Email!": "Veuillez saisir votre E-mail!",
|
||||
"Please input your ID card number!": "Veuillez entrer votre numéro de carte d'identité !",
|
||||
"Please input your address!": "Veuillez saisir votre adresse !",
|
||||
"Please input your affiliation!": "Veuillez entrer votre affiliation !",
|
||||
"Please input your display name!": "Veuillez entrer votre nom d'affichage !",
|
||||
"Please input your personal name!": "Veuillez entrer votre nom personnel !",
|
||||
"Please input your phone number!": "Veuillez entrer votre numéro de téléphone!",
|
||||
"Please select your country/region!": "Veuillez sélectionner votre pays/région!",
|
||||
"Terms of Use": "Conditions d'utilisation",
|
||||
"The input is not valid Email!": "L'entrée n'est pas un email valide !",
|
||||
"The input is not valid Phone!": "L'entrée n'est pas un téléphone valide !",
|
||||
"Unknown Check Type": "Type de vérification inconnu",
|
||||
"Username": "Nom d'utilisateur",
|
||||
"Username - Tooltip": "Nom d'utilisateur - Info-bulle",
|
||||
"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"
|
||||
},
|
||||
"syncer": {
|
||||
"Affiliation table": "Affiliation table",
|
||||
"Affiliation table - Tooltip": "Affiliation table - Tooltip",
|
||||
"Avatar base URL": "Avatar base URL",
|
||||
"Avatar base URL - Tooltip": "Avatar base URL - Tooltip",
|
||||
"Casdoor column": "Casdoor column",
|
||||
"Column name": "Column name",
|
||||
"Column type": "Column type",
|
||||
"Database": "Database",
|
||||
"Database - Tooltip": "Database - Tooltip",
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
"Table - Tooltip": "Table - Tooltip",
|
||||
"Table columns": "Table columns",
|
||||
"Table columns - Tooltip": "Table columns - Tooltip",
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
"Affiliation table": "Tableau d'affiliation",
|
||||
"Affiliation table - Tooltip": "Tableau d'affiliation - infobulle",
|
||||
"Avatar base URL": "URL de base de l'avatar",
|
||||
"Avatar base URL - Tooltip": "URL de base de l'avatar - Infobulle",
|
||||
"Casdoor column": "Colonne Casdoor",
|
||||
"Column name": "Nom de colonne",
|
||||
"Column type": "Type de colonne",
|
||||
"Database": "Base de données",
|
||||
"Database - Tooltip": "Base de données - infobulle",
|
||||
"Database type": "Type de base de données",
|
||||
"Database type - Tooltip": "Type de base de données - infobulle",
|
||||
"Edit Syncer": "Editer le synchro",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Est haché",
|
||||
"Sync interval": "Intervalle de synchronisation",
|
||||
"Sync interval - Tooltip": "Intervalle de synchronisation - infobulle",
|
||||
"Table": "Tableau",
|
||||
"Table - Tooltip": "Table - Infobulle",
|
||||
"Table columns": "Colonnes du tableau",
|
||||
"Table columns - Tooltip": "Colonnes du tableau - Infobulle",
|
||||
"Table primary key": "Clé primaire de la table",
|
||||
"Table primary key - Tooltip": "Clé primaire du tableau - infobulle"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
"Access token": "Jeton d'accès",
|
||||
"Authorization code": "Code d'autorisation",
|
||||
"Edit Token": "Modifier le jeton",
|
||||
"Expires in": "Expire dans",
|
||||
"Scope": "Périmètre d'application",
|
||||
"Token type": "Type de jeton"
|
||||
},
|
||||
"user": {
|
||||
"\" + destType + \" reset": "\" + destType + \" reset",
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"\" + destType + \" reset": "reset \" + destType + \"",
|
||||
"3rd-party logins": "Connexions de tiers",
|
||||
"3rd-party logins - Tooltip": "Use third-party apps to log in",
|
||||
"Address": "Address",
|
||||
"Address": "Adresses",
|
||||
"Address - Tooltip": "Unique string-style identifier",
|
||||
"Affiliation": "Affiliation",
|
||||
"Affiliation - Tooltip": "Unique string-style identifier",
|
||||
"Bio": "Bio",
|
||||
"Bio - Tooltip": "Bio - Tooltip",
|
||||
"Cancel": "Cancel",
|
||||
"Code Sent": "Code Sent",
|
||||
"Country/Region": "Country/Region",
|
||||
"Bio - Tooltip": "Bio - Infobulle",
|
||||
"Cancel": "Abandonner",
|
||||
"Code Sent": "Code envoyé",
|
||||
"Country/Region": "Pays/Région",
|
||||
"Country/Region - Tooltip": "Country/Region",
|
||||
"Edit User": "Edit User",
|
||||
"Edit User": "Editer l'utilisateur",
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
"Homepage": "Page d'accueil",
|
||||
"Homepage - Tooltip": "Page d'accueil - infobulle",
|
||||
"ID card": "Carte d'identité",
|
||||
"Input your email": "Entrez votre adresse e-mail",
|
||||
"Input your phone number": "Entrez votre numéro de téléphone",
|
||||
"Is admin": "Est administrateur",
|
||||
"Is admin - Tooltip": "Is the application administrator",
|
||||
"Is deleted": "Is deleted",
|
||||
"Is deleted - Tooltip": "Is deleted - Tooltip",
|
||||
"Is forbidden": "Is forbidden",
|
||||
"Is deleted": "Est supprimé",
|
||||
"Is deleted - Tooltip": "Est supprimé - infobulle",
|
||||
"Is forbidden": "Est interdit",
|
||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||
"Is global admin": "Is global admin",
|
||||
"Is global admin": "Est un administrateur global",
|
||||
"Is global admin - Tooltip": "Is the application global administrator",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New phone": "New phone",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
"Password": "Password",
|
||||
"Password Set": "Password Set",
|
||||
"Properties": "Properties",
|
||||
"Re-enter New": "Re-enter New",
|
||||
"Link": "Lier",
|
||||
"Location": "Localisation",
|
||||
"Location - Tooltip": "Localisation - Infobulle",
|
||||
"Modify password...": "Modifier le mot de passe...",
|
||||
"New Email": "Nouvel e-mail",
|
||||
"New Password": "Nouveau mot de passe",
|
||||
"New phone": "Nouveau téléphone",
|
||||
"OK": "Ok",
|
||||
"Old Password": "Ancien mot de passe",
|
||||
"Password": "Mot de passe",
|
||||
"Password Set": "Mot de passe défini",
|
||||
"Properties": "Propriétés",
|
||||
"Re-enter New": "Nouvelle entrée",
|
||||
"Reset Email...": "Reset Email...",
|
||||
"Reset Phone...": "Reset Phone...",
|
||||
"Select a photo...": "Select a photo...",
|
||||
"Set Password": "Set Password",
|
||||
"Set new profile picture": "Set new profile picture",
|
||||
"Set password...": "Set password...",
|
||||
"Tag": "Tag",
|
||||
"Reset Phone...": "Réinitialiser le téléphone...",
|
||||
"Select a photo...": "Sélectionnez une photo...",
|
||||
"Set Password": "Définir le mot de passe",
|
||||
"Set new profile picture": "Définir une nouvelle photo de profil",
|
||||
"Set password...": "Définir le mot de passe...",
|
||||
"Tag": "Étiquette",
|
||||
"Tag - Tooltip": "Unique string-style identifier",
|
||||
"Title": "Title",
|
||||
"Title": "Titre de la page",
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
"Two passwords you typed do not match.": "Les deux mots de passe que vous avez tapés ne correspondent pas.",
|
||||
"Unlink": "Délier",
|
||||
"Upload (.xlsx)": "Télécharger (.xlsx)",
|
||||
"Upload a photo": "Télécharger une photo",
|
||||
"input password": "saisir le mot de passe"
|
||||
},
|
||||
"webhook": {
|
||||
"Content type": "Content type",
|
||||
"Content type - Tooltip": "Content type - Tooltip",
|
||||
"Edit Webhook": "Edit Webhook",
|
||||
"Events": "Events",
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"Content type": "Type de contenu",
|
||||
"Content type - Tooltip": "Type de contenu - infobulle",
|
||||
"Edit Webhook": "Modifier le Webhook",
|
||||
"Events": "Évènements",
|
||||
"Events - Tooltip": "Événements - Info-bulle",
|
||||
"Headers": "En-têtes",
|
||||
"Headers - Tooltip": "En-têtes - Infobulle",
|
||||
"Is user extended": "Est un utilisateur étendu",
|
||||
"Is user extended - Tooltip": "Est un utilisateur étendu - infobulle",
|
||||
"Method": "Méthode",
|
||||
"Method - Tooltip": "Méthode - Infobulle",
|
||||
"Name": "Nom",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
"URL - Tooltip": "URL - Info-bulle",
|
||||
"Value": "Valeur"
|
||||
}
|
||||
}
|
@ -1,431 +1,484 @@
|
||||
{
|
||||
"account": {
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"My Account": "My Account",
|
||||
"Settings for your account": "Settings for your account",
|
||||
"Sign Up": "Sign Up"
|
||||
"Login": "ログイン",
|
||||
"Logout": "ログアウト",
|
||||
"My Account": "マイアカウント",
|
||||
"Settings for your account": "アカウントの設定",
|
||||
"Sign Up": "新規登録"
|
||||
},
|
||||
"application": {
|
||||
"Edit Application": "Edit Application",
|
||||
"Enable code signin": "Enable code signin",
|
||||
"Edit Application": "アプリケーションを編集",
|
||||
"Enable code signin": "コードサインインを有効にする",
|
||||
"Enable code signin - Tooltip": "Enable code signin - Tooltip",
|
||||
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
|
||||
"Enable signup": "Enable signup",
|
||||
"Enable signup": "サインアップを有効にする",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Password ON": "Password ON",
|
||||
"File uploaded successfully": "ファイルが正常にアップロードされました",
|
||||
"Password ON": "パスワードON",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Redirect URL": "Redirect URL",
|
||||
"Redirect URLs": "Redirect URLs",
|
||||
"Please select a HTML file": "HTMLファイルを選択してください",
|
||||
"Redirect URL": "リダイレクトURL",
|
||||
"Redirect URLs": "リダイレクトURL",
|
||||
"Redirect URLs - Tooltip": "List of redirect addresses after successful login",
|
||||
"Refresh token expire": "Refresh token expire",
|
||||
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Refresh token expire": "トークンの更新の期限が切れます",
|
||||
"Refresh token expire - Tooltip": "トークンの有効期限を更新する - ツールチップ",
|
||||
"Signin session": "サインインセッション",
|
||||
"Signup items": "アイテムの登録",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Test prompt page..": "Test prompt page..",
|
||||
"Test signin page..": "Test signin page..",
|
||||
"Test signup page..": "Test signup page..",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Test prompt page..": "テストプロンプトページ...",
|
||||
"Test signin page..": "サインインテストページ...",
|
||||
"Test signup page..": "登録ページのテスト",
|
||||
"Token expire": "トークンの有効期限",
|
||||
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
|
||||
"Token format": "トークンのフォーマット",
|
||||
"Token format - Tooltip": "トークンフォーマット - ツールチップ"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "ビットサイズ",
|
||||
"Bit size - Tooltip": "ビットサイズ - ツールチップ",
|
||||
"Copy private key": "秘密鍵をコピー",
|
||||
"Copy public key": "公開鍵をコピー",
|
||||
"Crypto algorithm": "暗号化アルゴリズム",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "秘密鍵をダウンロード",
|
||||
"Download public key": "公開鍵をダウンロード",
|
||||
"Edit Cert": "Certを編集",
|
||||
"Expire in years": "有効期限",
|
||||
"Expire in years - Tooltip": "年間有効期限 - ツールチップ",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "秘密鍵を正常にクリップボードにコピーしました",
|
||||
"Public key": "公開キー",
|
||||
"Public key - Tooltip": "Public key - Tooltip",
|
||||
"Public key copied to clipboard successfully": "公開鍵を正常にクリップボードにコピーしました",
|
||||
"Scope": "スコープ",
|
||||
"Scope - Tooltip": "スコープ → ツールチップ",
|
||||
"Type": "タイプ",
|
||||
"Type - Tooltip": "タイプ → ツールチップ"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
"Empty Code": "Empty Code",
|
||||
"Enter your code": "Enter your code",
|
||||
"Phone code": "Phone code",
|
||||
"Please input your phone verification code!": "Please input your phone verification code!",
|
||||
"Please input your verification code!": "Please input your verification code!",
|
||||
"Send Code": "Send Code",
|
||||
"Sending Code": "Sending Code",
|
||||
"Submit and complete": "Submit and complete"
|
||||
"Code You Received": "受け取ったコード",
|
||||
"Email code": "Emailコード",
|
||||
"Empty Code": "空のコード",
|
||||
"Enter your code": "コードを入力してください",
|
||||
"Phone code": "電話番号",
|
||||
"Please input your phone verification code!": "電話番号を入力してください!",
|
||||
"Please input your verification code!": "認証コードを入力してください!",
|
||||
"Send Code": "コードを送信",
|
||||
"Sending Code": "コードを送信中",
|
||||
"Submit and complete": "提出して完了"
|
||||
},
|
||||
"forget": {
|
||||
"Account": "Account",
|
||||
"Change Password": "Change Password",
|
||||
"Choose email or phone": "Choose email or phone",
|
||||
"Confirm": "Confirm",
|
||||
"Next Step": "Next Step",
|
||||
"Password": "Password",
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Account": "アカウント",
|
||||
"Change Password": "パスワードの変更",
|
||||
"Choose email or phone": "Eメールまたは電話番号を選択",
|
||||
"Confirm": "確認する",
|
||||
"Next Step": "次のステップ",
|
||||
"Password": "パスワード",
|
||||
"Please input your username!": "ユーザー名を入力してください!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Verify": "Verify"
|
||||
"Retrieve password": "パスワードの取得",
|
||||
"Verify": "確認する"
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Action": "アクション",
|
||||
"Add": "追加",
|
||||
"Affiliation URL": "アフィリエイトURL",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
"Application": "Application",
|
||||
"Applications": "Applications",
|
||||
"Applications that require authentication": "Applications that require authentication",
|
||||
"Avatar": "Avatar",
|
||||
"Application": "アプリケーション",
|
||||
"Applications": "アプリケーション",
|
||||
"Applications that require authentication": "認証が必要なアプリケーション",
|
||||
"Avatar": "アバター",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Back Home": "ホーム",
|
||||
"Captcha": "Captcha",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
"Certs": "Certs",
|
||||
"Client IP": "クライアント IP",
|
||||
"Created time": "作成日時",
|
||||
"Default avatar": "デフォルトのアバター",
|
||||
"Default avatar - Tooltip": "default avatar",
|
||||
"Delete": "Delete",
|
||||
"Description": "Description",
|
||||
"Delete": "削除",
|
||||
"Description": "説明",
|
||||
"Description - Tooltip": "Related descriptive information",
|
||||
"Display name": "Display name",
|
||||
"Display name": "表示名",
|
||||
"Display name - Tooltip": "Name shown to users, repeatable",
|
||||
"Down": "Down",
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Down": "下",
|
||||
"Edit": "編集",
|
||||
"Email": "Eメールアドレス",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL": "URLを忘れた",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Home",
|
||||
"Home": "ホーム",
|
||||
"Home - Tooltip": "Application homepage",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "random string",
|
||||
"Is enabled": "Is enabled",
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Is enabled": "有効にする",
|
||||
"Is enabled - Tooltip": "有効にする - ツールチップ",
|
||||
"LDAPs": "LDAP",
|
||||
"LDAPs - Tooltip": "LDAP - ツールチップ",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Method": "Method",
|
||||
"Name": "Name",
|
||||
"Master password": "マスターパスワード",
|
||||
"Master password - Tooltip": "マスターパスワード - ツールチップ",
|
||||
"Method": "方法",
|
||||
"Name": "名前",
|
||||
"Name - Tooltip": "Unique string-style identifier",
|
||||
"OAuth providers": "OAuth providers",
|
||||
"Organization": "Organization",
|
||||
"OAuth providers": "OAuthプロバイダー",
|
||||
"Organization": "組織",
|
||||
"Organization - Tooltip": "The group the user belongs to",
|
||||
"Organizations": "Organizations",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Organizations": "組織",
|
||||
"Password": "パスワード",
|
||||
"Password - Tooltip": "パスワード → ツールチップ",
|
||||
"Password salt": "パスワードソルト設定",
|
||||
"Password salt - Tooltip": "Random parameters used for password encryption",
|
||||
"Password type": "Password type",
|
||||
"Password type": "パスワードの種類",
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Permissions": "アクセス許可",
|
||||
"Personal name": "個人名",
|
||||
"Phone": "電話番号",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix": "電話プレフィクス",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Preview",
|
||||
"Preview": "プレビュー",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Provider": "Provider",
|
||||
"Providers": "Providers",
|
||||
"Provider": "プロバイダー",
|
||||
"Providers": "プロバイダー",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Records": "Records",
|
||||
"Records": "レコード",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Resources": "リソース",
|
||||
"Roles": "ロール",
|
||||
"Save": "保存",
|
||||
"Save & Exit": "保存して終了",
|
||||
"Signin URL": "サインインURL",
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL": "サインアップURL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Timestamp": "タイムスタンプ",
|
||||
"Tokens": "トークン",
|
||||
"URL": "URL",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
"User containers": "User containers",
|
||||
"User type": "User type",
|
||||
"Up": "上へ",
|
||||
"User": "ユーザー",
|
||||
"User - Tooltip": "ユーザー → ツールチップ",
|
||||
"User containers": "ユーザーコンテナ",
|
||||
"User type": "ユーザーの種類",
|
||||
"User type - Tooltip": "Permission role owned by the user",
|
||||
"Users": "Users",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Users": "ユーザー",
|
||||
"Users under all organizations": "すべての組織のユーザー",
|
||||
"Webhooks": "Webhooks",
|
||||
"{total} in total": "{total} in total"
|
||||
"{total} in total": "合計 {total}"
|
||||
},
|
||||
"ldap": {
|
||||
"Address": "Address",
|
||||
"Admin": "Admin",
|
||||
"Address": "住所",
|
||||
"Admin": "管理者",
|
||||
"Admin - Tooltip": "LDAP server admin CN or ID",
|
||||
"Admin Password": "Admin Password",
|
||||
"Admin Password": "管理者パスワード",
|
||||
"Admin Password - Tooltip": "LDAP server admin password",
|
||||
"Auto Sync": "Auto Sync",
|
||||
"Auto Sync": "自動同期",
|
||||
"Auto Sync - Tooltip": "Auto sync config, disable if is 0",
|
||||
"Base DN": "Base DN",
|
||||
"Base DN": "ベースDN",
|
||||
"Base DN - Tooltip": "LDAP search base DN",
|
||||
"CN": "CN",
|
||||
"Edit LDAP": "Edit LDAP",
|
||||
"Email": "Email",
|
||||
"Group Id": "Group Id",
|
||||
"Edit LDAP": "LDAP を編集",
|
||||
"Email": "Eメールアドレス",
|
||||
"Group Id": "グループ ID",
|
||||
"ID": "ID",
|
||||
"Last Sync": "Last Sync",
|
||||
"Phone": "Phone",
|
||||
"Server": "Server",
|
||||
"Server Host": "Server Host",
|
||||
"Last Sync": "前回の同期",
|
||||
"Phone": "電話番号",
|
||||
"Server": "サーバー",
|
||||
"Server Host": "サーバーホスト",
|
||||
"Server Host - Tooltip": "LDAP server host",
|
||||
"Server Name": "Server Name",
|
||||
"Server Name": "サーバー名",
|
||||
"Server Name - Tooltip": "LDAP server config display name",
|
||||
"Server Port": "Server Port",
|
||||
"Server Port": "サーバーポート",
|
||||
"Server Port - Tooltip": "LDAP server port",
|
||||
"Sync": "Sync",
|
||||
"The Auto Sync option will sync all users to specify organization": "The Auto Sync option will sync all users to specify organization",
|
||||
"Sync": "同期",
|
||||
"The Auto Sync option will sync all users to specify organization": "自動同期オプションは、組織を指定するためにすべてのユーザーを同期します",
|
||||
"UidNumber / Uid": "UidNumber / Uid"
|
||||
},
|
||||
"login": {
|
||||
"Auto sign in": "Auto sign in",
|
||||
"Continue with": "Continue with",
|
||||
"Email or phone": "Email or phone",
|
||||
"Forgot password?": "Forgot password?",
|
||||
"Invalid Email or phone": "Invalid Email or phone",
|
||||
"No account?": "No account?",
|
||||
"Or sign in with another account": "Or sign in with another account",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Please input your code!": "Please input your code!",
|
||||
"Please input your password!": "Please input your password!",
|
||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||
"Sign In": "Sign In",
|
||||
"Sign in with code": "Sign in with code",
|
||||
"Sign in with password": "Sign in with password",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"sign up now": "sign up now",
|
||||
"username, Email or phone": "username, Email or phone"
|
||||
"Auto sign in": "自動サインイン",
|
||||
"Continue with": "次で続ける",
|
||||
"Email or phone": "Eメールまたは電話番号",
|
||||
"Forgot password?": "パスワードを忘れましたか?",
|
||||
"Invalid Email or phone": "メールアドレスまたは電話番号が正しくありません",
|
||||
"No account?": "アカウントがありませんか?",
|
||||
"Or sign in with another account": "または別のアカウントでサインイン",
|
||||
"Password": "パスワード",
|
||||
"Password - Tooltip": "パスワード → ツールチップ",
|
||||
"Please input your code!": "コードを入力してください!",
|
||||
"Please input your password!": "パスワードを入力してください!",
|
||||
"Please input your password, at least 6 characters!": "6文字以上でパスワードを入力してください!",
|
||||
"Please input your username, Email or phone!": "ユーザー名、メールアドレスまたは電話番号を入力してください。",
|
||||
"Sign In": "サインイン",
|
||||
"Sign in with code": "コードでサインイン",
|
||||
"Sign in with password": "パスワードでサインイン",
|
||||
"Sign in with {type}": "{type} でサインイン",
|
||||
"Signing in...": "サインイン中...",
|
||||
"The input is not valid Email or Phone!": "入力されたメールアドレスまたは電話番号が正しくありません。",
|
||||
"To access": "アクセスするには",
|
||||
"sign up now": "今すぐサインアップ",
|
||||
"username, Email or phone": "ユーザー名、メールアドレスまたは電話番号"
|
||||
},
|
||||
"organization": {
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Favicon": "Favicon",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Default avatar": "デフォルトのアバター",
|
||||
"Edit Organization": "組織を編集",
|
||||
"Favicon": "ファビコン",
|
||||
"Soft deletion": "ソフト削除",
|
||||
"Soft deletion - Tooltip": "ソフト削除 - ツールチップ",
|
||||
"Website URL": "Website URL",
|
||||
"Website URL - Tooltip": "Unique string-style identifier"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "アクション",
|
||||
"Actions - Tooltip": "アクション → ツールチップ",
|
||||
"Edit Permission": "権限を編集",
|
||||
"Effect": "効果",
|
||||
"Effect - Tooltip": "エフェクト - ツールチップ",
|
||||
"Resource type": "リソースタイプ",
|
||||
"Resource type - Tooltip": "リソースタイプ - ツールチップ",
|
||||
"Resources": "リソース"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
"Bucket": "Bucket",
|
||||
"Access key": "アクセスキー",
|
||||
"Access key - Tooltip": "アクセスキー → ツールチップ",
|
||||
"Bucket": "バケツ入りバケツ",
|
||||
"Bucket - Tooltip": "Storage bucket name",
|
||||
"Can not parse Metadata": "Can not parse Metadata",
|
||||
"Category": "Category",
|
||||
"Can not parse Metadata": "メタデータをパースできません",
|
||||
"Category": "カテゴリ",
|
||||
"Category - Tooltip": "Unique string-style identifier",
|
||||
"Client ID": "Client ID",
|
||||
"Client ID": "クライアント ID",
|
||||
"Client ID - Tooltip": "Unique string-style identifier",
|
||||
"Client ID 2": "Client ID 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
|
||||
"Client secret": "Client secret",
|
||||
"Client ID 2": "クライアント ID 2",
|
||||
"Client ID 2 - Tooltip": "クライアント ID 2 - ツールチップ",
|
||||
"Client secret": "クライアントシークレット",
|
||||
"Client secret - Tooltip": "Unique string-style identifier",
|
||||
"Client secret 2": "Client secret 2",
|
||||
"Client secret 2": "クライアントシークレット 2",
|
||||
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
|
||||
"Copy": "Copy",
|
||||
"Domain": "Domain",
|
||||
"Copy": "コピー",
|
||||
"Domain": "ドメイン",
|
||||
"Domain - Tooltip": "Storage endpoint custom domain",
|
||||
"Edit Provider": "Edit Provider",
|
||||
"Edit Provider": "プロバイダーを編集",
|
||||
"Email Content": "Email Content",
|
||||
"Email Content - Tooltip": "Unique string-style identifier",
|
||||
"Email Title": "Email Title",
|
||||
"Email Title": "メールタイトル",
|
||||
"Email Title - Tooltip": "Unique string-style identifier",
|
||||
"Endpoint": "Endpoint",
|
||||
"Endpoint (Intranet)": "Endpoint (Intranet)",
|
||||
"Host": "Host",
|
||||
"Endpoint (Intranet)": "エンドポイント (イントラネット)",
|
||||
"Host": "ホスト",
|
||||
"Host - Tooltip": "Unique string-style identifier",
|
||||
"IdP": "IdP",
|
||||
"IdP public key": "IdP public key",
|
||||
"Issuer URL": "Issuer URL",
|
||||
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Metadata": "Metadata",
|
||||
"Metadata - Tooltip": "Metadata - Tooltip",
|
||||
"Method": "Method",
|
||||
"Issuer URL - Tooltip": "Issuer URL - ツールチップ",
|
||||
"Link copied to clipboard successfully": "リンクをクリップボードにコピーしました",
|
||||
"Metadata": "メタデータ",
|
||||
"Metadata - Tooltip": "メタデータ - ツールチップ",
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"Name": "名前",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Port": "Port",
|
||||
"Parse Metadata successfully": "メタデータの解析に成功",
|
||||
"Port": "ポート",
|
||||
"Port - Tooltip": "Unique string-style identifier",
|
||||
"Provider URL": "Provider URL",
|
||||
"Provider URL": "プロバイダー URL",
|
||||
"Provider URL - Tooltip": "Unique string-style identifier",
|
||||
"Region ID": "Region ID",
|
||||
"Region ID - Tooltip": "Region ID - Tooltip",
|
||||
"Region endpoint for Internet": "Region endpoint for Internet",
|
||||
"Region endpoint for Intranet": "Region endpoint for Intranet",
|
||||
"Region ID": "地域ID",
|
||||
"Region ID - Tooltip": "リージョンID - ツールチップ",
|
||||
"Region endpoint for Internet": "インターネットのリージョンエンドポイント",
|
||||
"Region endpoint for Intranet": "イントラネットのリージョンエンドポイント",
|
||||
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"Secret access key": "Secret access key",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
|
||||
"Sign Name": "Sign Name",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - ツールチップ",
|
||||
"SP Entity ID": "SP ID",
|
||||
"Secret access key": "シークレットアクセスキー",
|
||||
"SecretAccessKey - Tooltip": "シークレットアクセスキー - ツールチップ",
|
||||
"Sign Name": "署名名",
|
||||
"Sign Name - Tooltip": "Unique string-style identifier",
|
||||
"Sign request": "Sign request",
|
||||
"Sign request - Tooltip": "Sign request - Tooltip",
|
||||
"Signin HTML": "Signin HTML",
|
||||
"Signin HTML - Edit": "Signin HTML - Edit",
|
||||
"Sign request": "サインリクエスト",
|
||||
"Sign request - Tooltip": "サインリクエスト - ツールチップ",
|
||||
"Signin HTML": "サインインHTML",
|
||||
"Signin HTML - Edit": "ログイン HTML - 編集",
|
||||
"Signin HTML - Tooltip": "Signin HTML - Tooltip",
|
||||
"Signup HTML": "Signup HTML",
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Signup HTML - Tooltip",
|
||||
"Template Code": "Template Code",
|
||||
"Signup HTML": "HTMLの登録",
|
||||
"Signup HTML - Edit": "HTMLの登録 - 編集",
|
||||
"Signup HTML - Tooltip": "サインアップ HTML - ツールチップ",
|
||||
"Template Code": "テンプレートコード",
|
||||
"Template Code - Tooltip": "Unique string-style identifier",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"Terms of Use - Tooltip": "Terms of Use - Tooltip",
|
||||
"Type": "Type",
|
||||
"Terms of Use": "利用規約",
|
||||
"Terms of Use - Tooltip": "利用規約 - ツールチップ",
|
||||
"Type": "タイプ",
|
||||
"Type - Tooltip": "Unique string-style identifier",
|
||||
"alertType": "alertType",
|
||||
"canSignIn": "canSignIn",
|
||||
"canSignUp": "canSignUp",
|
||||
"canUnlink": "canUnlink",
|
||||
"prompted": "prompted",
|
||||
"required": "required",
|
||||
"rule": "rule",
|
||||
"visible": "visible"
|
||||
"prompted": "プロンプトされた",
|
||||
"required": "必須",
|
||||
"rule": "ルール",
|
||||
"visible": "表示"
|
||||
},
|
||||
"record": {
|
||||
"Is Triggered": "Is Triggered"
|
||||
"Is Triggered": "トリガーされます"
|
||||
},
|
||||
"resource": {
|
||||
"Application": "Application",
|
||||
"Copy Link": "Copy Link",
|
||||
"File name": "File name",
|
||||
"File size": "File size",
|
||||
"Format": "Format",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Parent": "Parent",
|
||||
"Tag": "Tag",
|
||||
"Type": "Type",
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
"Application": "アプリケーション",
|
||||
"Copy Link": "リンクをコピー",
|
||||
"File name": "ファイル名",
|
||||
"File size": "ファイルのサイズ",
|
||||
"Format": "書式",
|
||||
"Link copied to clipboard successfully": "リンクをクリップボードにコピーしました",
|
||||
"Parent": "親",
|
||||
"Tag": "タグ",
|
||||
"Type": "タイプ",
|
||||
"Upload a file...": "ファイルをアップロード...",
|
||||
"User": "ユーザー"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "役割を編集",
|
||||
"Sub roles": "サブロール",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "サブユーザー",
|
||||
"Sub users - Tooltip": "サブ ユーザー - Tooltip"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
"Decline": "Decline",
|
||||
"Have account?": "Have account?",
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
"The input is not valid Phone!": "The input is not valid Phone!",
|
||||
"Unknown Check Type": "Unknown Check Type",
|
||||
"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"
|
||||
"Accept": "同意する",
|
||||
"Confirm": "確認する",
|
||||
"Decline": "同意しない",
|
||||
"Have account?": "アカウントをお持ちですか?",
|
||||
"Please accept the agreement!": "契約に同意してください!",
|
||||
"Please click the below button to sign in": "サインインするには以下のボタンをクリックしてください",
|
||||
"Please confirm your password!": "パスワードを確認してください!",
|
||||
"Please input the correct ID card number!": "正しいIDカード番号を入力してください!",
|
||||
"Please input your Email!": "メールアドレスを入力してください!",
|
||||
"Please input your ID card number!": "IDカード番号を入力してください!",
|
||||
"Please input your address!": "住所を入力してください!",
|
||||
"Please input your affiliation!": "所属を入力してください!",
|
||||
"Please input your display name!": "表示名を入力してください。",
|
||||
"Please input your personal name!": "個人名を入力してください!",
|
||||
"Please input your phone number!": "電話番号を入力してください!",
|
||||
"Please select your country/region!": "あなたの国/地域を選択してください!",
|
||||
"Terms of Use": "利用規約",
|
||||
"The input is not valid Email!": "入力されたメールアドレスが無効です!",
|
||||
"The input is not valid Phone!": "入力された電話番号が正しくありません!",
|
||||
"Unknown Check Type": "不明なチェックタイプ",
|
||||
"Username": "ユーザー名",
|
||||
"Username - Tooltip": "ユーザー名 - ツールチップ",
|
||||
"Your account has been created!": "あなたのアカウントが作成されました!",
|
||||
"Your confirmed password is inconsistent with the password!": "確認されたパスワードがパスワードと一致していません!",
|
||||
"sign in now": "今すぐサインイン"
|
||||
},
|
||||
"syncer": {
|
||||
"Affiliation table": "Affiliation table",
|
||||
"Affiliation table - Tooltip": "Affiliation table - Tooltip",
|
||||
"Avatar base URL": "Avatar base URL",
|
||||
"Avatar base URL - Tooltip": "Avatar base URL - Tooltip",
|
||||
"Casdoor column": "Casdoor column",
|
||||
"Column name": "Column name",
|
||||
"Column type": "Column type",
|
||||
"Database": "Database",
|
||||
"Database - Tooltip": "Database - Tooltip",
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
"Table - Tooltip": "Table - Tooltip",
|
||||
"Table columns": "Table columns",
|
||||
"Table columns - Tooltip": "Table columns - Tooltip",
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
"Affiliation table": "アフィリエイトテーブル",
|
||||
"Affiliation table - Tooltip": "アフィリエイトテーブル - ツールチップ",
|
||||
"Avatar base URL": "アバターベースURL",
|
||||
"Avatar base URL - Tooltip": "アバターベースURL - ツールチップ",
|
||||
"Casdoor column": "キャスドアの列",
|
||||
"Column name": "カラム名",
|
||||
"Column type": "列の種類",
|
||||
"Database": "データベース",
|
||||
"Database - Tooltip": "データベース → ツールチップ",
|
||||
"Database type": "データベースの種類",
|
||||
"Database type - Tooltip": "データベース タイプ - ツールチップ",
|
||||
"Edit Syncer": "同期ツールを編集",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "ハッシュされました",
|
||||
"Sync interval": "同期間隔",
|
||||
"Sync interval - Tooltip": "同期間隔 - ツールチップ",
|
||||
"Table": "表",
|
||||
"Table - Tooltip": "表 → ツールチップ",
|
||||
"Table columns": "表の列",
|
||||
"Table columns - Tooltip": "テーブル列 - ツールチップ",
|
||||
"Table primary key": "テーブルのプライマリキー",
|
||||
"Table primary key - Tooltip": "テーブルのプライマリキー - ツールチップ"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
"Access token": "アクセストークン",
|
||||
"Authorization code": "認証コード",
|
||||
"Edit Token": "トークンを編集",
|
||||
"Expires in": "有効期限:",
|
||||
"Scope": "スコープ",
|
||||
"Token type": "トークンの種類"
|
||||
},
|
||||
"user": {
|
||||
"\" + destType + \" reset": "\" + destType + \" reset",
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins": "サードパーティーのログイン",
|
||||
"3rd-party logins - Tooltip": "Use third-party apps to log in",
|
||||
"Address": "Address",
|
||||
"Address": "住所",
|
||||
"Address - Tooltip": "Unique string-style identifier",
|
||||
"Affiliation": "Affiliation",
|
||||
"Affiliation - Tooltip": "Unique string-style identifier",
|
||||
"Bio": "Bio",
|
||||
"Bio - Tooltip": "Bio - Tooltip",
|
||||
"Cancel": "Cancel",
|
||||
"Code Sent": "Code Sent",
|
||||
"Country/Region": "Country/Region",
|
||||
"Bio": "略歴",
|
||||
"Bio - Tooltip": "バイオチップ(ツールチップ)",
|
||||
"Cancel": "キャンセル",
|
||||
"Code Sent": "コードを送信しました",
|
||||
"Country/Region": "国/地域",
|
||||
"Country/Region - Tooltip": "Country/Region",
|
||||
"Edit User": "Edit User",
|
||||
"Edit User": "ユーザーを編集",
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
"Homepage": "ホームページ",
|
||||
"Homepage - Tooltip": "ホームページ - ツールチップ",
|
||||
"ID card": "IDカード",
|
||||
"Input your email": "メールアドレスを入力してください",
|
||||
"Input your phone number": "電話番号を入力してください",
|
||||
"Is admin": "管理者",
|
||||
"Is admin - Tooltip": "Is the application administrator",
|
||||
"Is deleted": "Is deleted",
|
||||
"Is deleted - Tooltip": "Is deleted - Tooltip",
|
||||
"Is forbidden": "Is forbidden",
|
||||
"Is deleted": "削除された",
|
||||
"Is deleted - Tooltip": "削除されます - ツールチップ",
|
||||
"Is forbidden": "禁止されている",
|
||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||
"Is global admin": "Is global admin",
|
||||
"Is global admin": "グローバル管理者",
|
||||
"Is global admin - Tooltip": "Is the application global administrator",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New phone": "New phone",
|
||||
"Link": "リンク",
|
||||
"Location": "場所",
|
||||
"Location - Tooltip": "場所 → ツールチップ",
|
||||
"Modify password...": "パスワードを変更...",
|
||||
"New Email": "新しいメール",
|
||||
"New Password": "新しいパスワード",
|
||||
"New phone": "新しい電話番号",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
"Password": "Password",
|
||||
"Password Set": "Password Set",
|
||||
"Properties": "Properties",
|
||||
"Re-enter New": "Re-enter New",
|
||||
"Old Password": "古いパスワード",
|
||||
"Password": "パスワード",
|
||||
"Password Set": "パスワード設定",
|
||||
"Properties": "プロパティー",
|
||||
"Re-enter New": "新しい入力",
|
||||
"Reset Email...": "Reset Email...",
|
||||
"Reset Phone...": "Reset Phone...",
|
||||
"Select a photo...": "Select a photo...",
|
||||
"Set Password": "Set Password",
|
||||
"Set new profile picture": "Set new profile picture",
|
||||
"Set password...": "Set password...",
|
||||
"Tag": "Tag",
|
||||
"Reset Phone...": "電話番号をリセット...",
|
||||
"Select a photo...": "写真を選択...",
|
||||
"Set Password": "パスワードを設定",
|
||||
"Set new profile picture": "新しいプロフィール画像を設定",
|
||||
"Set password...": "パスワードを設定...",
|
||||
"Tag": "タグ",
|
||||
"Tag - Tooltip": "Unique string-style identifier",
|
||||
"Title": "Title",
|
||||
"Title": "タイトル",
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
"Two passwords you typed do not match.": "入力したパスワードが一致しません。",
|
||||
"Unlink": "リンクを解除",
|
||||
"Upload (.xlsx)": "アップロード (.xlsx)",
|
||||
"Upload a photo": "写真をアップロード",
|
||||
"input password": "パスワードを入力"
|
||||
},
|
||||
"webhook": {
|
||||
"Content type": "Content type",
|
||||
"Content type - Tooltip": "Content type - Tooltip",
|
||||
"Edit Webhook": "Edit Webhook",
|
||||
"Events": "Events",
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"Content type": "コンテンツタイプ",
|
||||
"Content type - Tooltip": "コンテンツ タイプ - ツールチップ",
|
||||
"Edit Webhook": "Webhookを編集",
|
||||
"Events": "イベント",
|
||||
"Events - Tooltip": "イベント → ツールチップ",
|
||||
"Headers": "ヘッダー",
|
||||
"Headers - Tooltip": "ヘッダー - ツールチップ",
|
||||
"Is user extended": "ユーザーが拡張されました",
|
||||
"Is user extended - Tooltip": "ユーザーが拡張されています - ツールチップ",
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "方法 - ツールチップ",
|
||||
"Name": "名前",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
"URL - Tooltip": "URL → ツールチップ",
|
||||
"Value": "値"
|
||||
}
|
||||
}
|
@ -33,6 +33,29 @@
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Bit size",
|
||||
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||
"Copy private key": "Copy private key",
|
||||
"Copy public key": "Copy public key",
|
||||
"Crypto algorithm": "Crypto algorithm",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "Download private key",
|
||||
"Download public key": "Download public key",
|
||||
"Edit Cert": "Edit Cert",
|
||||
"Expire in years": "Expire in years",
|
||||
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key - Tooltip",
|
||||
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||
"Public key": "Public key",
|
||||
"Public key - Tooltip": "Public key - Tooltip",
|
||||
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||
"Scope": "Scope",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
@ -69,6 +92,7 @@
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Captcha": "Captcha",
|
||||
"Certs": "Certs",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
@ -109,6 +133,7 @@
|
||||
"Password salt - Tooltip": "Random parameters used for password encryption",
|
||||
"Password type": "Password type",
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Permissions": "Permissions",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone",
|
||||
@ -122,12 +147,15 @@
|
||||
"Records": "Records",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Roles": "Roles",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
@ -206,6 +234,16 @@
|
||||
"Website URL": "Website URL",
|
||||
"Website URL - Tooltip": "Unique string-style identifier"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
@ -301,6 +339,13 @@
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
"Sub users - Tooltip": "Sub users - Tooltip"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
@ -309,7 +354,9 @@
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input the correct ID card number!": "Please input the correct ID card number!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your ID card number!": "Please input your ID card number!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
@ -339,6 +386,8 @@
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
@ -375,6 +424,7 @@
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"ID card": "ID card",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
@ -410,6 +460,7 @@
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload (.xlsx)": "Upload (.xlsx)",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
},
|
||||
@ -421,6 +472,8 @@
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Is user extended": "Is user extended",
|
||||
"Is user extended - Tooltip": "Is user extended - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
|
@ -1,431 +1,484 @@
|
||||
{
|
||||
"account": {
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"My Account": "My Account",
|
||||
"Settings for your account": "Settings for your account",
|
||||
"Sign Up": "Sign Up"
|
||||
"Login": "Логин",
|
||||
"Logout": "Выйти",
|
||||
"My Account": "Мой аккаунт",
|
||||
"Settings for your account": "Настройки учетной записи",
|
||||
"Sign Up": "Регистрация"
|
||||
},
|
||||
"application": {
|
||||
"Edit Application": "Edit Application",
|
||||
"Enable code signin": "Enable code signin",
|
||||
"Enable code signin - Tooltip": "Enable code signin - Tooltip",
|
||||
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
|
||||
"Enable signup": "Enable signup",
|
||||
"Edit Application": "Изменить приложение",
|
||||
"Enable code signin": "Включить кодовый вход",
|
||||
"Enable code signin - Tooltip": "Включить вход с кодом - Tooltip",
|
||||
"Enable signin session - Tooltip": "Включить сеанс входа - Подсказка",
|
||||
"Enable signup": "Включить регистрацию",
|
||||
"Enable signup - Tooltip": "Whether to allow users to sign up",
|
||||
"File uploaded successfully": "File uploaded successfully",
|
||||
"Password ON": "Password ON",
|
||||
"File uploaded successfully": "Файл успешно загружен",
|
||||
"Password ON": "Пароль ВКЛ",
|
||||
"Password ON - Tooltip": "Whether to allow password login",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
"Redirect URL": "Redirect URL",
|
||||
"Redirect URLs": "Redirect URLs",
|
||||
"Please select a HTML file": "Пожалуйста, выберите HTML-файл",
|
||||
"Redirect URL": "URL перенаправления",
|
||||
"Redirect URLs": "Перенаправление URL",
|
||||
"Redirect URLs - Tooltip": "List of redirect addresses after successful login",
|
||||
"Refresh token expire": "Refresh token expire",
|
||||
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
|
||||
"Signin session": "Signin session",
|
||||
"Signup items": "Signup items",
|
||||
"Refresh token expire": "Срок действия обновления токена истекает",
|
||||
"Refresh token expire - Tooltip": "Срок обновления токена истекает - Подсказка",
|
||||
"Signin session": "Сессия входа",
|
||||
"Signup items": "Элементы регистрации",
|
||||
"Signup items - Tooltip": "Signup items that need to be filled in when users register",
|
||||
"Test prompt page..": "Test prompt page..",
|
||||
"Test signin page..": "Test signin page..",
|
||||
"Test signup page..": "Test signup page..",
|
||||
"Token expire": "Token expire",
|
||||
"Token expire - Tooltip": "Token expire - Tooltip",
|
||||
"Token format": "Token format",
|
||||
"Token format - Tooltip": "Token format - Tooltip"
|
||||
"Test prompt page..": "Тестовая страница запроса..",
|
||||
"Test signin page..": "Тестовая страница входа..",
|
||||
"Test signup page..": "Тестовая страница регистрации..",
|
||||
"Token expire": "Токен истекает",
|
||||
"Token expire - Tooltip": "Истек токен - Подсказка",
|
||||
"Token format": "Формат токена",
|
||||
"Token format - Tooltip": "Формат токена - Подсказка"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "Размер бита",
|
||||
"Bit size - Tooltip": "Размер бита - Подсказка",
|
||||
"Copy private key": "Копировать закрытый ключ",
|
||||
"Copy public key": "Копировать открытый ключ",
|
||||
"Crypto algorithm": "Алгоритм крипто",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "Скачать закрытый ключ",
|
||||
"Download public key": "Скачать открытый ключ",
|
||||
"Edit Cert": "Изменить сертификат",
|
||||
"Expire in years": "Истекает через годы",
|
||||
"Expire in years - Tooltip": "Истекает через годы - Подсказка",
|
||||
"Private key": "Приватный ключ",
|
||||
"Private key - Tooltip": "Приватный ключ - Подсказка",
|
||||
"Private key copied to clipboard successfully": "Приватный ключ скопирован в буфер обмена",
|
||||
"Public key": "Публичный ключ",
|
||||
"Public key - Tooltip": "Открытый ключ - Подсказка",
|
||||
"Public key copied to clipboard successfully": "Открытый ключ успешно скопирован в буфер обмена",
|
||||
"Scope": "Сфера охвата",
|
||||
"Scope - Tooltip": "Область применения - Подсказка",
|
||||
"Type": "Тип",
|
||||
"Type - Tooltip": "Тип - Подсказка"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "Code You Received",
|
||||
"Email code": "Email code",
|
||||
"Empty Code": "Empty Code",
|
||||
"Enter your code": "Enter your code",
|
||||
"Phone code": "Phone code",
|
||||
"Please input your phone verification code!": "Please input your phone verification code!",
|
||||
"Please input your verification code!": "Please input your verification code!",
|
||||
"Send Code": "Send Code",
|
||||
"Sending Code": "Sending Code",
|
||||
"Submit and complete": "Submit and complete"
|
||||
"Code You Received": "Полученный код",
|
||||
"Email code": "Код эл. почты",
|
||||
"Empty Code": "Пустой код",
|
||||
"Enter your code": "Введите ваш код",
|
||||
"Phone code": "Телефон",
|
||||
"Please input your phone verification code!": "Пожалуйста, введите код подтверждения!",
|
||||
"Please input your verification code!": "Пожалуйста, введите код подтверждения!",
|
||||
"Send Code": "Отправить код",
|
||||
"Sending Code": "Отправка кода",
|
||||
"Submit and complete": "Отправить и завершить"
|
||||
},
|
||||
"forget": {
|
||||
"Account": "Account",
|
||||
"Change Password": "Change Password",
|
||||
"Choose email or phone": "Choose email or phone",
|
||||
"Confirm": "Confirm",
|
||||
"Next Step": "Next Step",
|
||||
"Password": "Password",
|
||||
"Please input your username!": "Please input your username!",
|
||||
"Account": "Аккаунт",
|
||||
"Change Password": "Изменить пароль",
|
||||
"Choose email or phone": "Выберите адрес электронной почты или телефон",
|
||||
"Confirm": "Подтвердить",
|
||||
"Next Step": "Следующий шаг",
|
||||
"Password": "Пароль",
|
||||
"Please input your username!": "Пожалуйста, введите ваше имя пользователя!",
|
||||
"Reset": "Reset",
|
||||
"Retrieve password": "Retrieve password",
|
||||
"Verify": "Verify"
|
||||
"Retrieve password": "Получить пароль",
|
||||
"Verify": "Подтвердить"
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Action": "Действие",
|
||||
"Add": "Добавить",
|
||||
"Affiliation URL": "URL-адрес партнёра",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
"Application": "Application",
|
||||
"Applications": "Applications",
|
||||
"Applications that require authentication": "Applications that require authentication",
|
||||
"Avatar": "Avatar",
|
||||
"Application": "Приложение",
|
||||
"Applications": "Заявления",
|
||||
"Applications that require authentication": "Приложения, требующие аутентификации",
|
||||
"Avatar": "Аватар",
|
||||
"Avatar - Tooltip": "Avatar to show to others",
|
||||
"Back Home": "Back Home",
|
||||
"Captcha": "Captcha",
|
||||
"Client IP": "Client IP",
|
||||
"Created time": "Created time",
|
||||
"Default avatar": "Default avatar",
|
||||
"Back Home": "Назад",
|
||||
"Captcha": "Капча",
|
||||
"Certs": "Сертификаты",
|
||||
"Client IP": "IP клиента",
|
||||
"Created time": "Время создания",
|
||||
"Default avatar": "Аватар по умолчанию",
|
||||
"Default avatar - Tooltip": "default avatar",
|
||||
"Delete": "Delete",
|
||||
"Description": "Description",
|
||||
"Delete": "Удалить",
|
||||
"Description": "Описание",
|
||||
"Description - Tooltip": "Related descriptive information",
|
||||
"Display name": "Display name",
|
||||
"Display name": "Отображать имя",
|
||||
"Display name - Tooltip": "Name shown to users, repeatable",
|
||||
"Down": "Down",
|
||||
"Edit": "Edit",
|
||||
"Email": "Email",
|
||||
"Down": "Вниз",
|
||||
"Edit": "Редактирование",
|
||||
"Email": "Почта",
|
||||
"Email - Tooltip": "email",
|
||||
"Favicon - Tooltip": "Application icon",
|
||||
"Forget URL": "Forget URL",
|
||||
"Forget URL": "Забыть URL",
|
||||
"Forget URL - Tooltip": "Unique string-style identifier",
|
||||
"Home": "Home",
|
||||
"Home": "Домашний",
|
||||
"Home - Tooltip": "Application homepage",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "random string",
|
||||
"Is enabled": "Is enabled",
|
||||
"Is enabled - Tooltip": "Is enabled - Tooltip",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs - Tooltip": "LDAPs - Tooltip",
|
||||
"Is enabled": "Включено",
|
||||
"Is enabled - Tooltip": "Включено - Подсказка",
|
||||
"LDAPs": "LDAPы",
|
||||
"LDAPs - Tooltip": "LDAPs - Подсказки",
|
||||
"Logo - Tooltip": "App's image tag",
|
||||
"Master password": "Master password",
|
||||
"Master password - Tooltip": "Master password - Tooltip",
|
||||
"Method": "Method",
|
||||
"Name": "Name",
|
||||
"Master password": "Мастер-пароль",
|
||||
"Master password - Tooltip": "Мастер-пароль - Tooltip",
|
||||
"Method": "Метод",
|
||||
"Name": "Наименование",
|
||||
"Name - Tooltip": "Unique string-style identifier",
|
||||
"OAuth providers": "OAuth providers",
|
||||
"Organization": "Organization",
|
||||
"OAuth providers": "Поставщики OAuth",
|
||||
"Organization": "Организация",
|
||||
"Organization - Tooltip": "The group the user belongs to",
|
||||
"Organizations": "Organizations",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Organizations": "Организации",
|
||||
"Password": "Пароль",
|
||||
"Password - Tooltip": "Пароль - Подсказка",
|
||||
"Password salt": "Соль пароля",
|
||||
"Password salt - Tooltip": "Random parameters used for password encryption",
|
||||
"Password type": "Password type",
|
||||
"Password type": "Тип пароля",
|
||||
"Password type - Tooltip": "The form in which the password is stored in the database",
|
||||
"Personal name": "Personal name",
|
||||
"Phone": "Phone",
|
||||
"Permissions": "Права доступа",
|
||||
"Personal name": "Личное имя",
|
||||
"Phone": "Телефон",
|
||||
"Phone - Tooltip": "Phone",
|
||||
"Phone prefix": "Phone prefix",
|
||||
"Phone prefix": "Префикс телефона",
|
||||
"Phone prefix - Tooltip": "Mobile phone number prefix, used to distinguish countries or regions",
|
||||
"Preview": "Preview",
|
||||
"Preview": "Предпросмотр",
|
||||
"Preview - Tooltip": "The form in which the password is stored in the database",
|
||||
"Provider": "Provider",
|
||||
"Providers": "Providers",
|
||||
"Provider": "Поставщик",
|
||||
"Providers": "Поставщики",
|
||||
"Providers - Tooltip": "List of third-party applications that can be used to log in",
|
||||
"Records": "Records",
|
||||
"Records": "Отчеты",
|
||||
"Request URI": "Request URI",
|
||||
"Resources": "Resources",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Signin URL": "Signin URL",
|
||||
"Resources": "Ресурсы",
|
||||
"Roles": "Роли",
|
||||
"Save": "Сохранить",
|
||||
"Save & Exit": "Сохранить и выйти",
|
||||
"Signin URL": "URL входа",
|
||||
"Signin URL - Tooltip": "sign in url",
|
||||
"Signup URL": "Signup URL",
|
||||
"Signup URL": "URL регистрации",
|
||||
"Signup URL - Tooltip": "sign up url",
|
||||
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
|
||||
"Signup application": "Signup application",
|
||||
"Signup application - Tooltip": "Signup application - Tooltip",
|
||||
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
|
||||
"Swagger": "Swagger",
|
||||
"Syncers": "Syncers",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Syncers": "Синхронизаторы",
|
||||
"Timestamp": "Отметка времени",
|
||||
"Tokens": "Жетоны",
|
||||
"URL": "URL",
|
||||
"Up": "Up",
|
||||
"User": "User",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
"User containers": "User containers",
|
||||
"User type": "User type",
|
||||
"Up": "Вверх",
|
||||
"User": "Пользователь",
|
||||
"User - Tooltip": "Пользователь - Подсказка",
|
||||
"User containers": "Контейнеры",
|
||||
"User type": "Тип пользователя",
|
||||
"User type - Tooltip": "Permission role owned by the user",
|
||||
"Users": "Users",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Webhooks": "Webhooks",
|
||||
"{total} in total": "{total} in total"
|
||||
"Users": "Пользователи",
|
||||
"Users under all organizations": "Пользователи из всех организаций",
|
||||
"Webhooks": "Вебхуки",
|
||||
"{total} in total": "{total} всего"
|
||||
},
|
||||
"ldap": {
|
||||
"Address": "Address",
|
||||
"Admin": "Admin",
|
||||
"Address": "Адрес",
|
||||
"Admin": "Админ",
|
||||
"Admin - Tooltip": "LDAP server admin CN or ID",
|
||||
"Admin Password": "Admin Password",
|
||||
"Admin Password": "Пароль администратора",
|
||||
"Admin Password - Tooltip": "LDAP server admin password",
|
||||
"Auto Sync": "Auto Sync",
|
||||
"Auto Sync": "Автосинхронизация",
|
||||
"Auto Sync - Tooltip": "Auto sync config, disable if is 0",
|
||||
"Base DN": "Base DN",
|
||||
"Base DN": "Базовый DN",
|
||||
"Base DN - Tooltip": "LDAP search base DN",
|
||||
"CN": "CN",
|
||||
"Edit LDAP": "Edit LDAP",
|
||||
"Email": "Email",
|
||||
"Group Id": "Group Id",
|
||||
"CN": "КНР",
|
||||
"Edit LDAP": "Редактировать LDAP",
|
||||
"Email": "Почта",
|
||||
"Group Id": "ID группы",
|
||||
"ID": "ID",
|
||||
"Last Sync": "Last Sync",
|
||||
"Phone": "Phone",
|
||||
"Server": "Server",
|
||||
"Server Host": "Server Host",
|
||||
"Last Sync": "Последняя синхронизация",
|
||||
"Phone": "Телефон",
|
||||
"Server": "Сервер",
|
||||
"Server Host": "Сервер хоста",
|
||||
"Server Host - Tooltip": "LDAP server host",
|
||||
"Server Name": "Server Name",
|
||||
"Server Name": "Имя сервера",
|
||||
"Server Name - Tooltip": "LDAP server config display name",
|
||||
"Server Port": "Server Port",
|
||||
"Server Port": "Порт Сервера",
|
||||
"Server Port - Tooltip": "LDAP server port",
|
||||
"Sync": "Sync",
|
||||
"The Auto Sync option will sync all users to specify organization": "The Auto Sync option will sync all users to specify organization",
|
||||
"Sync": "Синхр.",
|
||||
"The Auto Sync option will sync all users to specify organization": "Опция Автосинхронизация синхронизирует всех пользователей для указания организации",
|
||||
"UidNumber / Uid": "UidNumber / Uid"
|
||||
},
|
||||
"login": {
|
||||
"Auto sign in": "Auto sign in",
|
||||
"Continue with": "Continue with",
|
||||
"Email or phone": "Email or phone",
|
||||
"Forgot password?": "Forgot password?",
|
||||
"Invalid Email or phone": "Invalid Email or phone",
|
||||
"No account?": "No account?",
|
||||
"Or sign in with another account": "Or sign in with another account",
|
||||
"Password": "Password",
|
||||
"Password - Tooltip": "Password - Tooltip",
|
||||
"Please input your code!": "Please input your code!",
|
||||
"Please input your password!": "Please input your password!",
|
||||
"Please input your password, at least 6 characters!": "Please input your password, at least 6 characters!",
|
||||
"Please input your username, Email or phone!": "Please input your username, Email or phone!",
|
||||
"Sign In": "Sign In",
|
||||
"Sign in with code": "Sign in with code",
|
||||
"Sign in with password": "Sign in with password",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signing in...": "Signing in...",
|
||||
"The input is not valid Email or Phone!": "The input is not valid Email or Phone!",
|
||||
"To access": "To access",
|
||||
"sign up now": "sign up now",
|
||||
"username, Email or phone": "username, Email or phone"
|
||||
"Auto sign in": "Автовход",
|
||||
"Continue with": "Продолжить с",
|
||||
"Email or phone": "Электронная почта или телефон",
|
||||
"Forgot password?": "Забыли пароль?",
|
||||
"Invalid Email or phone": "Неверный адрес электронной почты или телефон",
|
||||
"No account?": "Нет учетной записи?",
|
||||
"Or sign in with another account": "Или войти с помощью другой учетной записи",
|
||||
"Password": "Пароль",
|
||||
"Password - Tooltip": "Пароль - Подсказка",
|
||||
"Please input your code!": "Пожалуйста, введите ваш код!",
|
||||
"Please input your password!": "Пожалуйста, введите ваш пароль!",
|
||||
"Please input your password, at least 6 characters!": "Пожалуйста, введите ваш пароль, по крайней мере 6 символов!",
|
||||
"Please input your username, Email or phone!": "Пожалуйста, введите ваше имя пользователя, адрес электронной почты или телефон!",
|
||||
"Sign In": "Войти",
|
||||
"Sign in with code": "Войти с помощью кода",
|
||||
"Sign in with password": "Войти с помощью пароля",
|
||||
"Sign in with {type}": "Войти с помощью {type}",
|
||||
"Signing in...": "Вход...",
|
||||
"The input is not valid Email or Phone!": "Введен неверный адрес электронной почты или телефон!",
|
||||
"To access": "На доступ",
|
||||
"sign up now": "зарегистрироваться",
|
||||
"username, Email or phone": "имя пользователя, адрес электронной почты или телефон"
|
||||
},
|
||||
"organization": {
|
||||
"Default avatar": "Default avatar",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Favicon": "Favicon",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Website URL": "Website URL",
|
||||
"Default avatar": "Аватар по умолчанию",
|
||||
"Edit Organization": "Изменить организацию",
|
||||
"Favicon": "Иконка",
|
||||
"Soft deletion": "Мягкое удаление",
|
||||
"Soft deletion - Tooltip": "Мягкое удаление - Подсказка",
|
||||
"Website URL": "URL сайта",
|
||||
"Website URL - Tooltip": "Unique string-style identifier"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "Действия",
|
||||
"Actions - Tooltip": "Действия - Подсказка",
|
||||
"Edit Permission": "Изменить права доступа",
|
||||
"Effect": "Эффект",
|
||||
"Effect - Tooltip": "Эффект - Подсказка",
|
||||
"Resource type": "Тип ресурса",
|
||||
"Resource type - Tooltip": "Тип ресурса - Подсказка",
|
||||
"Resources": "Ресурсы"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key - Tooltip": "Access key - Tooltip",
|
||||
"Bucket": "Bucket",
|
||||
"Access key": "Ключ доступа",
|
||||
"Access key - Tooltip": "Ключ доступа - Подсказка",
|
||||
"Bucket": "Ведро",
|
||||
"Bucket - Tooltip": "Storage bucket name",
|
||||
"Can not parse Metadata": "Can not parse Metadata",
|
||||
"Category": "Category",
|
||||
"Can not parse Metadata": "Невозможно разобрать метаданные",
|
||||
"Category": "Категория",
|
||||
"Category - Tooltip": "Unique string-style identifier",
|
||||
"Client ID": "Client ID",
|
||||
"Client ID": "ID клиента",
|
||||
"Client ID - Tooltip": "Unique string-style identifier",
|
||||
"Client ID 2": "Client ID 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
|
||||
"Client secret": "Client secret",
|
||||
"Client ID 2": "ID клиента 2",
|
||||
"Client ID 2 - Tooltip": "ID 2 - Подсказка",
|
||||
"Client secret": "Секрет клиента",
|
||||
"Client secret - Tooltip": "Unique string-style identifier",
|
||||
"Client secret 2": "Client secret 2",
|
||||
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
|
||||
"Copy": "Copy",
|
||||
"Domain": "Domain",
|
||||
"Client secret 2": "Секрет клиента 2",
|
||||
"Client secret 2 - Tooltip": "2 Клиент секрет - Подсказка",
|
||||
"Copy": "Копировать",
|
||||
"Domain": "Домен",
|
||||
"Domain - Tooltip": "Storage endpoint custom domain",
|
||||
"Edit Provider": "Edit Provider",
|
||||
"Edit Provider": "Изменить провайдера",
|
||||
"Email Content": "Email Content",
|
||||
"Email Content - Tooltip": "Unique string-style identifier",
|
||||
"Email Title": "Email Title",
|
||||
"Email Title": "Заголовок письма",
|
||||
"Email Title - Tooltip": "Unique string-style identifier",
|
||||
"Endpoint": "Endpoint",
|
||||
"Endpoint (Intranet)": "Endpoint (Intranet)",
|
||||
"Host": "Host",
|
||||
"Endpoint (Intranet)": "Точка входа (Intranet)",
|
||||
"Host": "Хост",
|
||||
"Host - Tooltip": "Unique string-style identifier",
|
||||
"IdP": "IdP",
|
||||
"IdP public key": "IdP public key",
|
||||
"Issuer URL": "Issuer URL",
|
||||
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Metadata": "Metadata",
|
||||
"Metadata - Tooltip": "Metadata - Tooltip",
|
||||
"Method": "Method",
|
||||
"IdP": "ИдП",
|
||||
"IdP public key": "Публичный ключ IdP",
|
||||
"Issuer URL": "URL эмитента",
|
||||
"Issuer URL - Tooltip": "URL эмитента - Tooltip",
|
||||
"Link copied to clipboard successfully": "Ссылка скопирована в буфер обмена",
|
||||
"Metadata": "Метаданные",
|
||||
"Metadata - Tooltip": "Метаданные - Подсказка",
|
||||
"Method": "Метод",
|
||||
"Method - Tooltip": "Login behaviors, QR code or silent authorization",
|
||||
"Name": "Name",
|
||||
"Name": "Наименование",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Port": "Port",
|
||||
"Parse Metadata successfully": "Анализ метаданных успешно завершен",
|
||||
"Port": "Порт",
|
||||
"Port - Tooltip": "Unique string-style identifier",
|
||||
"Provider URL": "Provider URL",
|
||||
"Provider URL": "URL провайдера",
|
||||
"Provider URL - Tooltip": "Unique string-style identifier",
|
||||
"Region ID": "Region ID",
|
||||
"Region ID - Tooltip": "Region ID - Tooltip",
|
||||
"Region endpoint for Internet": "Region endpoint for Internet",
|
||||
"Region endpoint for Intranet": "Region endpoint for Intranet",
|
||||
"Region ID": "ID региона",
|
||||
"Region ID - Tooltip": "Идентификатор региона - Подсказка",
|
||||
"Region endpoint for Internet": "Конечная точка региона для Интернета",
|
||||
"Region endpoint for Intranet": "Конечная точка региона Интранета",
|
||||
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"Secret access key": "Secret access key",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
|
||||
"Sign Name": "Sign Name",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Подсказка",
|
||||
"SP Entity ID": "Идентификатор сущности SP",
|
||||
"Secret access key": "Секретный ключ доступа",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Подсказка",
|
||||
"Sign Name": "Имя подписи",
|
||||
"Sign Name - Tooltip": "Unique string-style identifier",
|
||||
"Sign request": "Sign request",
|
||||
"Sign request - Tooltip": "Sign request - Tooltip",
|
||||
"Signin HTML": "Signin HTML",
|
||||
"Signin HTML - Edit": "Signin HTML - Edit",
|
||||
"Sign request": "Запрос на подпись",
|
||||
"Sign request - Tooltip": "Запрос на подпись - Подсказка",
|
||||
"Signin HTML": "Вход в HTML",
|
||||
"Signin HTML - Edit": "HTML вход - Редактирование",
|
||||
"Signin HTML - Tooltip": "Signin HTML - Tooltip",
|
||||
"Signup HTML": "Signup HTML",
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Signup HTML - Tooltip",
|
||||
"Template Code": "Template Code",
|
||||
"Signup HTML": "Регистрация HTML",
|
||||
"Signup HTML - Edit": "Регистрация HTML - Редактировать",
|
||||
"Signup HTML - Tooltip": "Регистрация HTML - Подсказка",
|
||||
"Template Code": "Код шаблона",
|
||||
"Template Code - Tooltip": "Unique string-style identifier",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"Terms of Use - Tooltip": "Terms of Use - Tooltip",
|
||||
"Type": "Type",
|
||||
"Terms of Use": "Условия использования",
|
||||
"Terms of Use - Tooltip": "Условия использования - Tooltip",
|
||||
"Type": "Тип",
|
||||
"Type - Tooltip": "Unique string-style identifier",
|
||||
"alertType": "alertType",
|
||||
"alertType": "тип оповещения",
|
||||
"canSignIn": "canSignIn",
|
||||
"canSignUp": "canSignUp",
|
||||
"canUnlink": "canUnlink",
|
||||
"prompted": "prompted",
|
||||
"required": "required",
|
||||
"rule": "rule",
|
||||
"visible": "visible"
|
||||
"prompted": "запрошено",
|
||||
"required": "обязательный",
|
||||
"rule": "правило",
|
||||
"visible": "видимый"
|
||||
},
|
||||
"record": {
|
||||
"Is Triggered": "Is Triggered"
|
||||
"Is Triggered": "Срабатывает"
|
||||
},
|
||||
"resource": {
|
||||
"Application": "Application",
|
||||
"Copy Link": "Copy Link",
|
||||
"File name": "File name",
|
||||
"File size": "File size",
|
||||
"Format": "Format",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Parent": "Parent",
|
||||
"Tag": "Tag",
|
||||
"Type": "Type",
|
||||
"Upload a file...": "Upload a file...",
|
||||
"User": "User"
|
||||
"Application": "Приложение",
|
||||
"Copy Link": "Скопировать ссылку",
|
||||
"File name": "Имя файла",
|
||||
"File size": "Размер файла",
|
||||
"Format": "Формат",
|
||||
"Link copied to clipboard successfully": "Ссылка скопирована в буфер обмена",
|
||||
"Parent": "Родитель",
|
||||
"Tag": "Тег",
|
||||
"Type": "Тип",
|
||||
"Upload a file...": "Загрузить файл...",
|
||||
"User": "Пользователь"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "Изменить роль",
|
||||
"Sub roles": "Суб роли",
|
||||
"Sub roles - Tooltip": "Суб роли - Tooltip",
|
||||
"Sub users": "Субпользователи",
|
||||
"Sub users - Tooltip": "Подпользователи - Подсказки"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "Accept",
|
||||
"Confirm": "Confirm",
|
||||
"Decline": "Decline",
|
||||
"Have account?": "Have account?",
|
||||
"Please accept the agreement!": "Please accept the agreement!",
|
||||
"Please click the below button to sign in": "Please click the below button to sign in",
|
||||
"Please confirm your password!": "Please confirm your password!",
|
||||
"Please input your Email!": "Please input your Email!",
|
||||
"Please input your address!": "Please input your address!",
|
||||
"Please input your affiliation!": "Please input your affiliation!",
|
||||
"Please input your display name!": "Please input your display name!",
|
||||
"Please input your personal name!": "Please input your personal name!",
|
||||
"Please input your phone number!": "Please input your phone number!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Terms of Use": "Terms of Use",
|
||||
"The input is not valid Email!": "The input is not valid Email!",
|
||||
"The input is not valid Phone!": "The input is not valid Phone!",
|
||||
"Unknown Check Type": "Unknown Check Type",
|
||||
"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"
|
||||
"Accept": "Принять",
|
||||
"Confirm": "Подтвердить",
|
||||
"Decline": "Отклонить",
|
||||
"Have account?": "Есть аккаунт?",
|
||||
"Please accept the agreement!": "Пожалуйста, примите соглашение!",
|
||||
"Please click the below button to sign in": "Пожалуйста, нажмите на кнопку ниже, чтобы войти",
|
||||
"Please confirm your password!": "Пожалуйста, подтвердите свой пароль!",
|
||||
"Please input the correct ID card number!": "Пожалуйста, введите правильный номер идентификационной карты!",
|
||||
"Please input your Email!": "Пожалуйста, введите ваш E-mail!",
|
||||
"Please input your ID card number!": "Пожалуйста, введите номер вашей идентификационной карты!",
|
||||
"Please input your address!": "Пожалуйста, введите ваш адрес!",
|
||||
"Please input your affiliation!": "Пожалуйста, введите вашу партнерство!",
|
||||
"Please input your display name!": "Пожалуйста, введите ваше отображаемое имя!",
|
||||
"Please input your personal name!": "Пожалуйста, введите ваше личное имя!",
|
||||
"Please input your phone number!": "Пожалуйста, введите ваш номер телефона!",
|
||||
"Please select your country/region!": "Пожалуйста, выберите вашу страну/регион!",
|
||||
"Terms of Use": "Условия использования",
|
||||
"The input is not valid Email!": "Ввод не является допустимым Email!",
|
||||
"The input is not valid Phone!": "Введен неверный телефон!",
|
||||
"Unknown Check Type": "Неизвестный тип проверки",
|
||||
"Username": "Имя пользователя",
|
||||
"Username - Tooltip": "Имя пользователя - Подсказка",
|
||||
"Your account has been created!": "Ваша учетная запись была создана!",
|
||||
"Your confirmed password is inconsistent with the password!": "Подтвержденный пароль не соответствует паролю!",
|
||||
"sign in now": "войти сейчас"
|
||||
},
|
||||
"syncer": {
|
||||
"Affiliation table": "Affiliation table",
|
||||
"Affiliation table - Tooltip": "Affiliation table - Tooltip",
|
||||
"Avatar base URL": "Avatar base URL",
|
||||
"Avatar base URL - Tooltip": "Avatar base URL - Tooltip",
|
||||
"Casdoor column": "Casdoor column",
|
||||
"Column name": "Column name",
|
||||
"Column type": "Column type",
|
||||
"Database": "Database",
|
||||
"Database - Tooltip": "Database - Tooltip",
|
||||
"Database type": "Database type",
|
||||
"Database type - Tooltip": "Database type - Tooltip",
|
||||
"Edit Syncer": "Edit Syncer",
|
||||
"Is hashed": "Is hashed",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Sync interval - Tooltip",
|
||||
"Table": "Table",
|
||||
"Table - Tooltip": "Table - Tooltip",
|
||||
"Table columns": "Table columns",
|
||||
"Table columns - Tooltip": "Table columns - Tooltip",
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
"Affiliation table": "Партнерская таблица",
|
||||
"Affiliation table - Tooltip": "Партнерская таблица - Подсказка",
|
||||
"Avatar base URL": "Базовый URL аватара",
|
||||
"Avatar base URL - Tooltip": "URL базы аватаров - Подсказка",
|
||||
"Casdoor column": "Колонка кастрюли",
|
||||
"Column name": "Название столбца",
|
||||
"Column type": "Тип столбца",
|
||||
"Database": "База данных",
|
||||
"Database - Tooltip": "База данных - Подсказка",
|
||||
"Database type": "Тип базы данных",
|
||||
"Database type - Tooltip": "Тип базы данных - Подсказка",
|
||||
"Edit Syncer": "Изменить синхронизатор",
|
||||
"Error text": "Error text",
|
||||
"Error text - Tooltip": "Error text - Tooltip",
|
||||
"Is hashed": "Хэшировано",
|
||||
"Sync interval": "Интервал синхронизации",
|
||||
"Sync interval - Tooltip": "Интервал синхронизации - Tooltip",
|
||||
"Table": "Таблица",
|
||||
"Table - Tooltip": "Таблица - Подсказки",
|
||||
"Table columns": "Столбцы таблицы",
|
||||
"Table columns - Tooltip": "Столбцы таблиц - Подсказка",
|
||||
"Table primary key": "Основной ключ таблицы",
|
||||
"Table primary key - Tooltip": "Основная таблица - Подсказка"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
"Edit Token": "Edit Token",
|
||||
"Expires in": "Expires in",
|
||||
"Scope": "Scope",
|
||||
"Token type": "Token type"
|
||||
"Access token": "Маркер доступа",
|
||||
"Authorization code": "Код авторизации",
|
||||
"Edit Token": "Изменить токен",
|
||||
"Expires in": "Истекает через",
|
||||
"Scope": "Сфера охвата",
|
||||
"Token type": "Тип токена"
|
||||
},
|
||||
"user": {
|
||||
"\" + destType + \" reset": "\" + destType + \" reset",
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"\" + destType + \" reset": "\" + destType + \" сброс",
|
||||
"3rd-party logins": "Сторонние логины",
|
||||
"3rd-party logins - Tooltip": "Use third-party apps to log in",
|
||||
"Address": "Address",
|
||||
"Address": "Адрес",
|
||||
"Address - Tooltip": "Unique string-style identifier",
|
||||
"Affiliation": "Affiliation",
|
||||
"Affiliation": "Партнёр",
|
||||
"Affiliation - Tooltip": "Unique string-style identifier",
|
||||
"Bio": "Bio",
|
||||
"Bio - Tooltip": "Bio - Tooltip",
|
||||
"Cancel": "Cancel",
|
||||
"Code Sent": "Code Sent",
|
||||
"Country/Region": "Country/Region",
|
||||
"Bio": "Био",
|
||||
"Bio - Tooltip": "Био - Подсказка",
|
||||
"Cancel": "Отмена",
|
||||
"Code Sent": "Код отправлен",
|
||||
"Country/Region": "Страна/регион",
|
||||
"Country/Region - Tooltip": "Country/Region",
|
||||
"Edit User": "Edit User",
|
||||
"Edit User": "Изменить пользователя",
|
||||
"Empty input!": "Empty input!",
|
||||
"Homepage": "Homepage",
|
||||
"Homepage - Tooltip": "Homepage - Tooltip",
|
||||
"Input your email": "Input your email",
|
||||
"Input your phone number": "Input your phone number",
|
||||
"Is admin": "Is admin",
|
||||
"Homepage": "Главная страница",
|
||||
"Homepage - Tooltip": "Главная страница - Подсказки",
|
||||
"ID card": "ID-карта",
|
||||
"Input your email": "Введите ваш email",
|
||||
"Input your phone number": "Введите ваш номер телефона",
|
||||
"Is admin": "Админ",
|
||||
"Is admin - Tooltip": "Is the application administrator",
|
||||
"Is deleted": "Is deleted",
|
||||
"Is deleted - Tooltip": "Is deleted - Tooltip",
|
||||
"Is forbidden": "Is forbidden",
|
||||
"Is deleted": "Удалено",
|
||||
"Is deleted - Tooltip": "Удалено - подсказка",
|
||||
"Is forbidden": "Запрещено",
|
||||
"Is forbidden - Tooltip": "Whether the account is disabled",
|
||||
"Is global admin": "Is global admin",
|
||||
"Is global admin": "Глобальный администратор",
|
||||
"Is global admin - Tooltip": "Is the application global administrator",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "Location - Tooltip",
|
||||
"Modify password...": "Modify password...",
|
||||
"New Email": "New Email",
|
||||
"New Password": "New Password",
|
||||
"New phone": "New phone",
|
||||
"OK": "OK",
|
||||
"Old Password": "Old Password",
|
||||
"Password": "Password",
|
||||
"Password Set": "Password Set",
|
||||
"Properties": "Properties",
|
||||
"Re-enter New": "Re-enter New",
|
||||
"Link": "Ссылка",
|
||||
"Location": "Местоположение",
|
||||
"Location - Tooltip": "Расположение - Подсказка",
|
||||
"Modify password...": "Изменить пароль...",
|
||||
"New Email": "Новое письмо",
|
||||
"New Password": "Новый пароль",
|
||||
"New phone": "Новый телефон",
|
||||
"OK": "ОК",
|
||||
"Old Password": "Старый пароль",
|
||||
"Password": "Пароль",
|
||||
"Password Set": "Пароль установлен",
|
||||
"Properties": "Свойства",
|
||||
"Re-enter New": "Введите еще раз",
|
||||
"Reset Email...": "Reset Email...",
|
||||
"Reset Phone...": "Reset Phone...",
|
||||
"Select a photo...": "Select a photo...",
|
||||
"Set Password": "Set Password",
|
||||
"Set new profile picture": "Set new profile picture",
|
||||
"Set password...": "Set password...",
|
||||
"Tag": "Tag",
|
||||
"Reset Phone...": "Сбросить телефон...",
|
||||
"Select a photo...": "Выберите фото...",
|
||||
"Set Password": "Установить пароль",
|
||||
"Set new profile picture": "Установить новое изображение профиля",
|
||||
"Set password...": "Установить пароль...",
|
||||
"Tag": "Тег",
|
||||
"Tag - Tooltip": "Unique string-style identifier",
|
||||
"Title": "Title",
|
||||
"Title": "Заголовок",
|
||||
"Title - Tooltip": "Title - Tooltip",
|
||||
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
|
||||
"Unlink": "Unlink",
|
||||
"Upload a photo": "Upload a photo",
|
||||
"input password": "input password"
|
||||
"Two passwords you typed do not match.": "Введенные пароли не совпадают.",
|
||||
"Unlink": "Отвязать",
|
||||
"Upload (.xlsx)": "Загрузить (.xlsx)",
|
||||
"Upload a photo": "Загрузить фото",
|
||||
"input password": "пароль для ввода"
|
||||
},
|
||||
"webhook": {
|
||||
"Content type": "Content type",
|
||||
"Content type - Tooltip": "Content type - Tooltip",
|
||||
"Edit Webhook": "Edit Webhook",
|
||||
"Events": "Events",
|
||||
"Events - Tooltip": "Events - Tooltip",
|
||||
"Headers": "Headers",
|
||||
"Headers - Tooltip": "Headers - Tooltip",
|
||||
"Method": "Method",
|
||||
"Method - Tooltip": "Method - Tooltip",
|
||||
"Name": "Name",
|
||||
"Content type": "Тип контента",
|
||||
"Content type - Tooltip": "Тип контента - Подсказка",
|
||||
"Edit Webhook": "Редактировать вебхук",
|
||||
"Events": "События",
|
||||
"Events - Tooltip": "События - Подсказка",
|
||||
"Headers": "Заголовки",
|
||||
"Headers - Tooltip": "Заголовки - Подсказки",
|
||||
"Is user extended": "Пользователь продлен",
|
||||
"Is user extended - Tooltip": "Расширен пользователь - Подсказка",
|
||||
"Method": "Метод",
|
||||
"Method - Tooltip": "Метод - Подсказка",
|
||||
"Name": "Наименование",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL - Tooltip",
|
||||
"Value": "Value"
|
||||
"URL - Tooltip": "URL - Подсказка",
|
||||
"Value": "Значение"
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
"Sign Up": "注册"
|
||||
},
|
||||
"application": {
|
||||
"Edit Application": "修改应用",
|
||||
"Edit Application": "编辑应用",
|
||||
"Enable code signin": "启用验证码登录",
|
||||
"Enable code signin - Tooltip": "是否允许用手机或邮箱验证码登录",
|
||||
"Enable signin session - Tooltip": "从应用登录Casdoor后,Casdoor是否保持会话",
|
||||
@ -33,6 +33,29 @@
|
||||
"Token format": "Access Token格式",
|
||||
"Token format - Tooltip": "Access Token格式"
|
||||
},
|
||||
"cert": {
|
||||
"Bit size": "位大小",
|
||||
"Bit size - Tooltip": "位大小 - 工具提示",
|
||||
"Copy private key": "复制私钥",
|
||||
"Copy public key": "复制公钥",
|
||||
"Crypto algorithm": "加密算法",
|
||||
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||
"Download private key": "下载私钥",
|
||||
"Download public key": "下载公钥",
|
||||
"Edit Cert": "编辑证书",
|
||||
"Expire in years": "有效期(年)",
|
||||
"Expire in years - Tooltip": "到期年份-工具提示",
|
||||
"Private key": "私钥",
|
||||
"Private key - Tooltip": "私钥 - 工具提示",
|
||||
"Private key copied to clipboard successfully": "私钥已成功复制到剪贴板",
|
||||
"Public key": "公钥",
|
||||
"Public key - Tooltip": "公钥 - 工具提示",
|
||||
"Public key copied to clipboard successfully": "公钥已成功复制到剪贴板",
|
||||
"Scope": "用途",
|
||||
"Scope - Tooltip": "范围 - 工具提示",
|
||||
"Type": "类型",
|
||||
"Type - Tooltip": "类型 - 工具提示"
|
||||
},
|
||||
"code": {
|
||||
"Code You Received": "验证码",
|
||||
"Email code": "邮箱验证码",
|
||||
@ -47,7 +70,7 @@
|
||||
},
|
||||
"forget": {
|
||||
"Account": "账号",
|
||||
"Change Password": "修改密码",
|
||||
"Change Password": "编辑密码",
|
||||
"Choose email or phone": "请选择邮箱或手机号验证",
|
||||
"Confirm": "验证密码",
|
||||
"Next Step": "下一步",
|
||||
@ -69,6 +92,7 @@
|
||||
"Avatar - Tooltip": "向其他人展示的头像",
|
||||
"Back Home": "返回到首页",
|
||||
"Captcha": "人机验证码",
|
||||
"Certs": "证书",
|
||||
"Client IP": "客户端IP",
|
||||
"Created time": "创建时间",
|
||||
"Default avatar": "默认头像",
|
||||
@ -79,7 +103,7 @@
|
||||
"Display name": "显示名称",
|
||||
"Display name - Tooltip": "显示名称",
|
||||
"Down": "下移",
|
||||
"Edit": "修改",
|
||||
"Edit": "编辑",
|
||||
"Email": "电子邮箱",
|
||||
"Email - Tooltip": "电子邮件:",
|
||||
"Favicon - Tooltip": "网站的图标",
|
||||
@ -91,7 +115,7 @@
|
||||
"ID - Tooltip": "唯一的随机字符串",
|
||||
"Is enabled": "已启用",
|
||||
"Is enabled - Tooltip": "是否启用",
|
||||
"LDAPs": "LDAPs",
|
||||
"LDAPs": "LDAP",
|
||||
"LDAPs - Tooltip": "LDAPs",
|
||||
"Logo - Tooltip": "应用程序向外展示的图标",
|
||||
"Master password": "万能密码",
|
||||
@ -109,6 +133,7 @@
|
||||
"Password salt - Tooltip": "用于密码加密的随机参数",
|
||||
"Password type": "密码类型",
|
||||
"Password type - Tooltip": "密码在数据库中存储的形式",
|
||||
"Permissions": "权限",
|
||||
"Personal name": "姓名",
|
||||
"Phone": "手机号",
|
||||
"Phone - Tooltip": "手机号",
|
||||
@ -116,18 +141,21 @@
|
||||
"Phone prefix - Tooltip": "移动电话号码前缀,用于区分国家或地区",
|
||||
"Preview": "预览",
|
||||
"Preview - Tooltip": "预览",
|
||||
"Provider": "Provider",
|
||||
"Provider": "提供商",
|
||||
"Providers": "提供商",
|
||||
"Providers - Tooltip": "第三方登录需要配置的提供方",
|
||||
"Records": "日志",
|
||||
"Request URI": "请求URI",
|
||||
"Resources": "资源",
|
||||
"Roles": "角色",
|
||||
"Save": "保存",
|
||||
"Save & Exit": "保存 & 退出",
|
||||
"Signin URL": "登录URL",
|
||||
"Signin URL - Tooltip": "用户的登录地址",
|
||||
"Signup URL": "注册URL",
|
||||
"Signup URL - Tooltip": "展示给用户的注册地址",
|
||||
"Signup application": "注册应用",
|
||||
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
|
||||
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
|
||||
"Swagger": "API文档",
|
||||
"Syncers": "同步器",
|
||||
@ -136,7 +164,7 @@
|
||||
"URL": "链接",
|
||||
"Up": "上移",
|
||||
"User": "用户",
|
||||
"User - Tooltip": "User - Tooltip",
|
||||
"User - Tooltip": "用户 - 工具提示",
|
||||
"User containers": "用户容器",
|
||||
"User type": "用户类型",
|
||||
"User type - Tooltip": "具有不同权限的用户角色",
|
||||
@ -154,11 +182,11 @@
|
||||
"Auto Sync": "自动同步",
|
||||
"Auto Sync - Tooltip": "自动同步配置,为0时禁用",
|
||||
"Base DN": "基本DN",
|
||||
"Base DN - Tooltip": "LDAP 搜索时的基本 DN",
|
||||
"Base DN - Tooltip": "LDAP搜索时的基 DN",
|
||||
"CN": "CN",
|
||||
"Edit LDAP": "编辑LDAP",
|
||||
"Email": "电子邮件",
|
||||
"Group Id": "组 Id",
|
||||
"Group Id": "组ID",
|
||||
"ID": "ID",
|
||||
"Last Sync": "最近同步",
|
||||
"Phone": "电话",
|
||||
@ -170,8 +198,8 @@
|
||||
"Server Port": "端口",
|
||||
"Server Port - Tooltip": "LDAP服务器端口号",
|
||||
"Sync": "同步",
|
||||
"The Auto Sync option will sync all users to specify organization": "The Auto Sync option will sync all users to specify organization",
|
||||
"UidNumber / Uid": "UidNumber / Uid"
|
||||
"The Auto Sync option will sync all users to specify organization": "自动同步选项将同步所有用户以指定组织",
|
||||
"UidNumber / Uid": "Uid号码 / Uid"
|
||||
},
|
||||
"login": {
|
||||
"Auto sign in": "下次自动登录",
|
||||
@ -199,33 +227,43 @@
|
||||
},
|
||||
"organization": {
|
||||
"Default avatar": "默认头像",
|
||||
"Edit Organization": "修改组织",
|
||||
"Edit Organization": "编辑组织",
|
||||
"Favicon": "图标",
|
||||
"Soft deletion": "软删除",
|
||||
"Soft deletion - Tooltip": "启用后,删除用户信息时不会在数据库彻底清除,只会标记为已删除状态",
|
||||
"Website URL": "网页地址",
|
||||
"Website URL - Tooltip": "网页地址"
|
||||
},
|
||||
"permission": {
|
||||
"Actions": "动作",
|
||||
"Actions - Tooltip": "授权的动作",
|
||||
"Edit Permission": "编辑权限",
|
||||
"Effect": "效果",
|
||||
"Effect - Tooltip": "允许还是拒绝",
|
||||
"Resource type": "资源类型",
|
||||
"Resource type - Tooltip": "授权资源的类型",
|
||||
"Resources": "资源"
|
||||
},
|
||||
"provider": {
|
||||
"Access key": "Access key",
|
||||
"Access key": "访问密钥",
|
||||
"Access key - Tooltip": "Access key",
|
||||
"Bucket": "存储桶",
|
||||
"Bucket - Tooltip": "Bucket名称",
|
||||
"Can not parse Metadata": "Can not parse Metadata",
|
||||
"Can not parse Metadata": "无法解析元数据",
|
||||
"Category": "分类",
|
||||
"Category - Tooltip": "分类",
|
||||
"Client ID": "Client ID",
|
||||
"Client ID": "客户端ID",
|
||||
"Client ID - Tooltip": "Client ID",
|
||||
"Client ID 2": "Client ID 2",
|
||||
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
|
||||
"Client secret": "Client secret",
|
||||
"Client ID 2": "客户端 ID 2",
|
||||
"Client ID 2 - Tooltip": "客户端 ID 2 - 工具提示",
|
||||
"Client secret": "客户端密钥",
|
||||
"Client secret - Tooltip": "Client secret",
|
||||
"Client secret 2": "Client secret 2",
|
||||
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
|
||||
"Copy": "Copy",
|
||||
"Client secret 2": "客户端密钥 2",
|
||||
"Client secret 2 - Tooltip": "客户端密钥 2 - 工具提示",
|
||||
"Copy": "复制",
|
||||
"Domain": "域名",
|
||||
"Domain - Tooltip": "存储节点自定义域名",
|
||||
"Edit Provider": "修改提供商",
|
||||
"Edit Provider": "编辑提供商",
|
||||
"Email Content": "邮件内容",
|
||||
"Email Content - Tooltip": "邮件内容",
|
||||
"Email Title": "邮件标题",
|
||||
@ -235,18 +273,18 @@
|
||||
"Host": "主机",
|
||||
"Host - Tooltip": "主机",
|
||||
"IdP": "IdP",
|
||||
"IdP public key": "IdP public key",
|
||||
"Issuer URL": "Issuer URL",
|
||||
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
|
||||
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
|
||||
"Metadata": "Metadata",
|
||||
"Metadata - Tooltip": "Metadata - Tooltip",
|
||||
"IdP public key": "IdP 公钥",
|
||||
"Issuer URL": "发行者网址",
|
||||
"Issuer URL - Tooltip": "发行者URL - 工具提示",
|
||||
"Link copied to clipboard successfully": "链接复制到剪贴板成功",
|
||||
"Metadata": "元数据",
|
||||
"Metadata - Tooltip": "元数据 - 工具提示",
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "登录行为,二维码或者静默授权登录",
|
||||
"Name": "名称",
|
||||
"Parse": "Parse",
|
||||
"Parse Metadata successfully": "Parse Metadata successfully",
|
||||
"Port": "端口号",
|
||||
"Parse Metadata successfully": "解析元数据成功",
|
||||
"Port": "端口",
|
||||
"Port - Tooltip": "端口号",
|
||||
"Provider URL": "提供商URL",
|
||||
"Provider URL - Tooltip": "提供商URL",
|
||||
@ -256,14 +294,14 @@
|
||||
"Region endpoint for Intranet": "地域节点 (内网)",
|
||||
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"Secret access key": "Secret access key",
|
||||
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - 工具提示",
|
||||
"SP Entity ID": "SP 实体 ID",
|
||||
"Secret access key": "秘密访问密钥",
|
||||
"SecretAccessKey - Tooltip": "访问密钥-工具提示",
|
||||
"Sign Name": "签名名称",
|
||||
"Sign Name - Tooltip": "签名名称",
|
||||
"Sign request": "Sign request",
|
||||
"Sign request - Tooltip": "Sign request - Tooltip",
|
||||
"Sign request": "签名请求",
|
||||
"Sign request - Tooltip": "签名请求 - 工具提示",
|
||||
"Signin HTML": "登录 HTML",
|
||||
"Signin HTML - Edit": "登录 HTML - 编辑",
|
||||
"Signin HTML - Tooltip": "登录 HTML - 工具提示",
|
||||
@ -276,14 +314,14 @@
|
||||
"Terms of Use - Tooltip": "使用条款 - 工具提示",
|
||||
"Type": "类型",
|
||||
"Type - Tooltip": "类型",
|
||||
"alertType": "alertType",
|
||||
"alertType": "警报类型",
|
||||
"canSignIn": "canSignIn",
|
||||
"canSignUp": "canSignUp",
|
||||
"canUnlink": "canUnlink",
|
||||
"prompted": "prompted",
|
||||
"prompted": "提示",
|
||||
"required": "必需",
|
||||
"rule": "rule",
|
||||
"visible": "visible"
|
||||
"rule": "规则",
|
||||
"visible": "可见"
|
||||
},
|
||||
"record": {
|
||||
"Is Triggered": "已触发"
|
||||
@ -292,8 +330,8 @@
|
||||
"Application": "应用",
|
||||
"Copy Link": "复制链接",
|
||||
"File name": "文件名",
|
||||
"File size": "文件大小",
|
||||
"Format": "文件格式",
|
||||
"File size": "大小",
|
||||
"Format": "格式",
|
||||
"Link copied to clipboard successfully": "链接已成功复制到剪贴板",
|
||||
"Parent": "属主",
|
||||
"Tag": "标签",
|
||||
@ -301,6 +339,13 @@
|
||||
"Upload a file...": "上传文件...",
|
||||
"User": "用户"
|
||||
},
|
||||
"role": {
|
||||
"Edit Role": "编辑角色",
|
||||
"Sub roles": "包含角色",
|
||||
"Sub roles - Tooltip": "当前角色所包含的子角色",
|
||||
"Sub users": "包含用户",
|
||||
"Sub users - Tooltip": "当前角色所包含的子用户"
|
||||
},
|
||||
"signup": {
|
||||
"Accept": "阅读并接受",
|
||||
"Confirm": "确认密码",
|
||||
@ -309,7 +354,9 @@
|
||||
"Please accept the agreement!": "请先同意用户协议!",
|
||||
"Please click the below button to sign in": "请点击下方按钮登录",
|
||||
"Please confirm your password!": "请再次确认您的密码!",
|
||||
"Please input the correct ID card number!": "请输入正确的身份证号!",
|
||||
"Please input your Email!": "请输入您的电子邮箱!",
|
||||
"Please input your ID card number!": "请输入您的身份证号!",
|
||||
"Please input your address!": "请输入您的地址!",
|
||||
"Please input your affiliation!": "请输入您所在的工作单位!",
|
||||
"Please input your display name!": "请输入您的显示名称!",
|
||||
@ -338,10 +385,12 @@
|
||||
"Database - Tooltip": "数据库名称",
|
||||
"Database type": "数据库类型",
|
||||
"Database type - Tooltip": "数据库类型",
|
||||
"Edit Syncer": "修改同步器",
|
||||
"Edit Syncer": "编辑同步器",
|
||||
"Error text": "错误信息",
|
||||
"Error text - Tooltip": "同步器连接数据库时发生的错误",
|
||||
"Is hashed": "是否参与哈希计算",
|
||||
"Sync interval": "同步间隔",
|
||||
"Sync interval - Tooltip": "单位为分钟",
|
||||
"Sync interval - Tooltip": "单位为秒",
|
||||
"Table": "表名",
|
||||
"Table - Tooltip": "数据库表名",
|
||||
"Table columns": "表格列",
|
||||
@ -350,9 +399,9 @@
|
||||
"Table primary key - Tooltip": "表主键,如id"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Access token": "访问令牌",
|
||||
"Authorization code": "授权码",
|
||||
"Edit Token": "修改令牌",
|
||||
"Edit Token": "编辑令牌",
|
||||
"Expires in": "有效期",
|
||||
"Scope": "范围",
|
||||
"Token type": "令牌类型"
|
||||
@ -371,10 +420,11 @@
|
||||
"Code Sent": "验证码已发送",
|
||||
"Country/Region": "国家/地区",
|
||||
"Country/Region - Tooltip": "国家/地区",
|
||||
"Edit User": "修改用户",
|
||||
"Edit User": "编辑用户",
|
||||
"Empty input!": "输入为空!",
|
||||
"Homepage": "个人主页",
|
||||
"Homepage - Tooltip": "个人主页链接",
|
||||
"ID card": "身份证号",
|
||||
"Input your email": "请输入邮箱",
|
||||
"Input your phone number": "输入手机号",
|
||||
"Is admin": "是管理员",
|
||||
@ -388,7 +438,7 @@
|
||||
"Link": "绑定",
|
||||
"Location": "城市",
|
||||
"Location - Tooltip": "居住地址所在的城市",
|
||||
"Modify password...": "修改密码...",
|
||||
"Modify password...": "编辑密码...",
|
||||
"New Email": "新邮箱",
|
||||
"New Password": "新密码",
|
||||
"New phone": "新手机号",
|
||||
@ -410,21 +460,24 @@
|
||||
"Title - Tooltip": "在单位/公司的职务",
|
||||
"Two passwords you typed do not match.": "两次输入的密码不匹配。",
|
||||
"Unlink": "解绑",
|
||||
"Upload (.xlsx)": "上传(.xlsx)",
|
||||
"Upload a photo": "上传头像",
|
||||
"input password": "输入密码"
|
||||
},
|
||||
"webhook": {
|
||||
"Content type": "Content type",
|
||||
"Content type": "内容类型",
|
||||
"Content type - Tooltip": "Content type",
|
||||
"Edit Webhook": "修改Webhook",
|
||||
"Edit Webhook": "编辑Webhook",
|
||||
"Events": "事件",
|
||||
"Events - Tooltip": "事件",
|
||||
"Headers": "协议头",
|
||||
"Headers - Tooltip": "HTTP协议头(键值对)",
|
||||
"Is user extended": "扩展用户字段",
|
||||
"Is user extended - Tooltip": "JSON里加入extendedUser来扩展用户字段",
|
||||
"Method": "方法",
|
||||
"Method - Tooltip": "HTTP方法",
|
||||
"Name": "名称",
|
||||
"URL": "URL",
|
||||
"URL": "网址",
|
||||
"URL - Tooltip": "URL",
|
||||
"Value": "值"
|
||||
}
|
||||
|
@ -5190,6 +5190,11 @@ file-loader@6.1.1:
|
||||
loader-utils "^2.0.0"
|
||||
schema-utils "^3.0.0"
|
||||
|
||||
file-saver@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
|
||||
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
|
43
xlsx/xlsx.go
Normal file
43
xlsx/xlsx.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2021 The casbin 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 xlsx
|
||||
|
||||
import (
|
||||
"github.com/casbin/casdoor/util"
|
||||
"github.com/tealeg/xlsx"
|
||||
)
|
||||
|
||||
func ReadXlsxFile(fileId string) [][]string {
|
||||
path := util.GetUploadXlsxPath(fileId)
|
||||
file, err := xlsx.OpenFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
res := [][]string{}
|
||||
for _, sheet := range file.Sheets {
|
||||
for _, row := range sheet.Rows {
|
||||
line := []string{}
|
||||
for _, cell := range row.Cells {
|
||||
text := cell.String()
|
||||
line = append(line, text)
|
||||
}
|
||||
res = append(res, line)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
22
xlsx/xlsx_test.go
Normal file
22
xlsx/xlsx_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2021 The casbin 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 xlsx
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestReadSheet(t *testing.T) {
|
||||
ticket := ReadXlsxFile("../../tmpFiles/example")
|
||||
println(ticket)
|
||||
}
|
Reference in New Issue
Block a user