mirror of
https://github.com/casdoor/casdoor.git
synced 2025-09-04 01:53:37 +08:00
Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f93aeb5350 | ||
![]() |
8fa681f883 | ||
![]() |
3b16406442 | ||
![]() |
fbc16ef124 | ||
![]() |
f26f56e88b | ||
![]() |
9cb633c9e2 | ||
![]() |
d0d059d42f | ||
![]() |
c184dc7f3a | ||
![]() |
2fa0890c11 | ||
![]() |
a0e2be7ba8 | ||
![]() |
09b389b1f7 | ||
![]() |
a23033758f | ||
![]() |
f7bc822087 | ||
![]() |
e533ff1ee1 | ||
![]() |
9f187f690e | ||
![]() |
fe5aa1f214 | ||
![]() |
eda742a848 | ||
![]() |
83df077a02 | ||
![]() |
ad6080e763 | ||
![]() |
c179324de4 | ||
![]() |
645716e485 | ||
![]() |
955e73ddd1 | ||
![]() |
2493ae9cfe | ||
![]() |
b5c80513fb | ||
![]() |
0653353be1 | ||
![]() |
d6778fb4e6 | ||
![]() |
fee7773839 | ||
![]() |
d47ac6b957 | ||
![]() |
857824df19 | ||
![]() |
1e98d1e11b | ||
![]() |
48ba88de2d | ||
![]() |
a3a142db39 | ||
![]() |
3bb7cc6b81 | ||
![]() |
1fb3249bfd | ||
![]() |
ff8f61a84c | ||
![]() |
a118879dc0 | ||
![]() |
386b673446 | ||
![]() |
6abd46fe81 | ||
![]() |
49d734d249 | ||
![]() |
f5b4cd7fab | ||
![]() |
76f322861a | ||
![]() |
124c28f1e1 | ||
![]() |
e0d9cc7ed1 | ||
![]() |
75c1ae4366 | ||
![]() |
d537377b31 | ||
![]() |
462ecce43b | ||
![]() |
a84664b55d | ||
![]() |
941c56e69e | ||
![]() |
a28b871a46 | ||
![]() |
387f5d58f7 | ||
![]() |
7d846b2060 | ||
![]() |
c1c2dcab38 | ||
![]() |
f9264f700b | ||
![]() |
f3af2a26aa | ||
![]() |
0ac69bde53 | ||
![]() |
70c99f0e59 |
@@ -70,6 +70,16 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
return
|
||||
}
|
||||
|
||||
if application.DisableSignin {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s has disabled users to signin"), application.Name))
|
||||
return
|
||||
}
|
||||
|
||||
if application.OrganizationObj != nil && application.OrganizationObj.DisableSignin {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s has disabled users to signin"), application.Organization))
|
||||
return
|
||||
}
|
||||
|
||||
allowed, err := object.CheckLoginPermission(userId, application)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
@@ -147,7 +157,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
c.ResponseError(c.T("auth:Challenge method should be S256"))
|
||||
return
|
||||
}
|
||||
code, err := object.GetOAuthCode(userId, clientId, form.Provider, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
code, err := object.GetOAuthCode(userId, clientId, form.Provider, form.SigninMethod, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
@@ -709,7 +719,8 @@ func (c *ApiController) Login() {
|
||||
|
||||
setHttpClient(idProvider, provider.Type)
|
||||
|
||||
if authForm.State != conf.GetConfigString("authState") && authForm.State != application.Name {
|
||||
stateApplicationName := strings.Split(authForm.State, "-org-")[0]
|
||||
if authForm.State != conf.GetConfigString("authState") && stateApplicationName != application.Name {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:State expected: %s, but got: %s"), conf.GetConfigString("authState"), authForm.State))
|
||||
return
|
||||
}
|
||||
@@ -778,7 +789,7 @@ func (c *ApiController) Login() {
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" || provider.Category == "SAML" {
|
||||
// Sign up via OAuth
|
||||
if application.EnableLinkWithEmail {
|
||||
if userInfo.Email != "" {
|
||||
@@ -807,7 +818,7 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
|
||||
if !providerItem.CanSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -40,6 +40,18 @@ func (c *ApiController) Enforce() {
|
||||
enforcerId := c.Input().Get("enforcerId")
|
||||
owner := c.Input().Get("owner")
|
||||
|
||||
params := []string{permissionId, modelId, resourceId, enforcerId, owner}
|
||||
nonEmpty := 0
|
||||
for _, param := range params {
|
||||
if param != "" {
|
||||
nonEmpty++
|
||||
}
|
||||
}
|
||||
if nonEmpty > 1 {
|
||||
c.ResponseError("Only one of the parameters (permissionId, modelId, resourceId, enforcerId, owner) should be provided")
|
||||
return
|
||||
}
|
||||
|
||||
if len(c.Ctx.Input.RequestBody) == 0 {
|
||||
c.ResponseError("The request body should not be empty")
|
||||
return
|
||||
@@ -169,6 +181,18 @@ func (c *ApiController) BatchEnforce() {
|
||||
enforcerId := c.Input().Get("enforcerId")
|
||||
owner := c.Input().Get("owner")
|
||||
|
||||
params := []string{permissionId, modelId, enforcerId, owner}
|
||||
nonEmpty := 0
|
||||
for _, param := range params {
|
||||
if param != "" {
|
||||
nonEmpty++
|
||||
}
|
||||
}
|
||||
if nonEmpty > 1 {
|
||||
c.ResponseError("Only one of the parameters (permissionId, modelId, enforcerId, owner) should be provided")
|
||||
return
|
||||
}
|
||||
|
||||
var requests [][]string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
||||
if err != nil {
|
||||
|
@@ -25,6 +25,7 @@ const (
|
||||
goCliRepo = "https://api.github.com/repos/casbin/casbin-go-cli/releases/latest"
|
||||
rustCliRepo = "https://api.github.com/repos/casbin-rs/casbin-rust-cli/releases/latest"
|
||||
pythonCliRepo = "https://api.github.com/repos/casbin/casbin-python-cli/releases/latest"
|
||||
dotnetCliRepo = "https://api.github.com/repos/casbin-net/casbin-dotnet-cli/releases/latest"
|
||||
downloadFolder = "bin"
|
||||
)
|
||||
|
||||
@@ -45,6 +46,7 @@ func getBinaryNames() map[string]string {
|
||||
java = "java"
|
||||
rust = "rust"
|
||||
python = "python"
|
||||
dotnet = "dotnet"
|
||||
)
|
||||
|
||||
arch := runtime.GOARCH
|
||||
@@ -65,6 +67,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-pc-windows-gnu", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-windows-%s.exe", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-windows-%s.exe", archNames.goArch),
|
||||
}
|
||||
case "darwin":
|
||||
return map[string]string{
|
||||
@@ -72,6 +75,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-apple-darwin", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-darwin-%s", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-darwin-%s", archNames.goArch),
|
||||
}
|
||||
case "linux":
|
||||
return map[string]string{
|
||||
@@ -79,6 +83,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-unknown-linux-gnu", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-linux-%s", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-linux-%s", archNames.goArch),
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
@@ -108,6 +113,11 @@ func getFinalBinaryName(lang string) string {
|
||||
return "casbin-python-cli.exe"
|
||||
}
|
||||
return "casbin-python-cli"
|
||||
case "dotnet":
|
||||
if runtime.GOOS == "windows" {
|
||||
return "casbin-dotnet-cli.exe"
|
||||
}
|
||||
return "casbin-dotnet-cli"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -347,6 +357,7 @@ func downloadCLI() error {
|
||||
"go": goCliRepo,
|
||||
"rust": rustCliRepo,
|
||||
"python": pythonCliRepo,
|
||||
"dotnet": dotnetCliRepo,
|
||||
}
|
||||
|
||||
for lang, repo := range repos {
|
||||
|
@@ -154,6 +154,14 @@ func (c *ApiController) DeleteEnforcer() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetPolicies
|
||||
// @Title GetPolicies
|
||||
// @Tag Enforcer API
|
||||
// @Description get policies
|
||||
// @Param id query string true "The id ( owner/name ) of enforcer"
|
||||
// @Param adapterId query string false "The adapter id"
|
||||
// @Success 200 {array} xormadapter.CasbinRule
|
||||
// @router /get-policies [get]
|
||||
func (c *ApiController) GetPolicies() {
|
||||
id := c.Input().Get("id")
|
||||
adapterId := c.Input().Get("adapterId")
|
||||
@@ -188,6 +196,41 @@ func (c *ApiController) GetPolicies() {
|
||||
c.ResponseOk(policies)
|
||||
}
|
||||
|
||||
// GetFilteredPolicies
|
||||
// @Title GetFilteredPolicies
|
||||
// @Tag Enforcer API
|
||||
// @Description get filtered policies with support for multiple filters via POST body
|
||||
// @Param id query string true "The id ( owner/name ) of enforcer"
|
||||
// @Param body body []object.Filter true "Array of filter objects for multiple filters"
|
||||
// @Success 200 {array} xormadapter.CasbinRule
|
||||
// @router /get-filtered-policies [post]
|
||||
func (c *ApiController) GetFilteredPolicies() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var filters []object.Filter
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &filters)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
filteredPolicies, err := object.GetFilteredPoliciesMulti(id, filters)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(filteredPolicies)
|
||||
}
|
||||
|
||||
// UpdatePolicy
|
||||
// @Title UpdatePolicy
|
||||
// @Tag Enforcer API
|
||||
// @Description update policy
|
||||
// @Param id query string true "The id ( owner/name ) of enforcer"
|
||||
// @Param body body []xormadapter.CasbinRule true "Array containing old and new policy"
|
||||
// @Success 200 {object} Response
|
||||
// @router /update-policy [post]
|
||||
func (c *ApiController) UpdatePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
@@ -207,6 +250,14 @@ func (c *ApiController) UpdatePolicy() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// AddPolicy
|
||||
// @Title AddPolicy
|
||||
// @Tag Enforcer API
|
||||
// @Description add policy
|
||||
// @Param id query string true "The id ( owner/name ) of enforcer"
|
||||
// @Param body body xormadapter.CasbinRule true "The policy to add"
|
||||
// @Success 200 {object} Response
|
||||
// @router /add-policy [post]
|
||||
func (c *ApiController) AddPolicy() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
@@ -226,6 +277,14 @@ func (c *ApiController) AddPolicy() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// RemovePolicy
|
||||
// @Title RemovePolicy
|
||||
// @Tag Enforcer API
|
||||
// @Description remove policy
|
||||
// @Param id query string true "The id ( owner/name ) of enforcer"
|
||||
// @Param body body xormadapter.CasbinRule true "The policy to remove"
|
||||
// @Success 200 {object} Response
|
||||
// @router /remove-policy [post]
|
||||
func (c *ApiController) RemovePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
|
@@ -16,6 +16,8 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@@ -188,3 +190,73 @@ func (c *ApiController) VerifyInvitation() {
|
||||
|
||||
c.ResponseOk(payment, attachInfo)
|
||||
}
|
||||
|
||||
// SendInvitation
|
||||
// @Title VerifyInvitation
|
||||
// @Tag Invitation API
|
||||
// @Description verify invitation
|
||||
// @Param id query string true "The id ( owner/name ) of the invitation"
|
||||
// @Param body body []string true "The details of the invitation"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /send-invitation [post]
|
||||
func (c *ApiController) SendInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var destinations []string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &destinations)
|
||||
|
||||
if !c.IsAdmin() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
invitation, err := object.GetInvitation(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if invitation == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("invitation:Invitation %s does not exist"), id))
|
||||
return
|
||||
}
|
||||
|
||||
organization, err := object.GetOrganization(fmt.Sprintf("admin/%s", invitation.Owner))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByOrganizationName(invitation.Owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s should have one application at least"), invitation.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
provider, err := application.GetEmailProvider("Invitation")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:please add an Email provider to the \"Providers\" list for the application: %s"), invitation.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
content := provider.Metadata
|
||||
|
||||
content = strings.ReplaceAll(content, "%code", invitation.Code)
|
||||
content = strings.ReplaceAll(content, "%link", invitation.GetInvitationLink(c.Ctx.Request.Host, application.Name))
|
||||
|
||||
err = object.SendEmail(provider, provider.Title, content, destinations, organization.DisplayName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -187,6 +188,11 @@ func (c *ApiController) DeleteResource() {
|
||||
}
|
||||
_, resource.Name = refineFullFilePath(resource.Name)
|
||||
|
||||
tag := c.Input().Get("tag")
|
||||
if tag == "Direct" {
|
||||
resource.Name = path.Join(provider.PathPrefix, resource.Name)
|
||||
}
|
||||
|
||||
err = object.DeleteFile(provider, resource.Name, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
@@ -144,7 +144,7 @@ func (c *ApiController) SendEmail() {
|
||||
content = strings.Replace(content, string(matchContent), "", -1)
|
||||
|
||||
for _, receiver := range emailForm.Receivers {
|
||||
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
|
||||
err = object.SendEmail(provider, emailForm.Title, content, []string{receiver}, emailForm.Sender)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
@@ -551,6 +551,12 @@ func (c *ApiController) SetPassword() {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the new password is the same as the current password
|
||||
if !object.CheckPasswordNotSameAsCurrent(targetUser, newPassword, organization) {
|
||||
c.ResponseError(c.T("user:The new password must be different from your current password"))
|
||||
return
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByUser(targetUser)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
@@ -435,9 +435,15 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
|
||||
switch destType {
|
||||
case object.VerifyTypeEmail:
|
||||
id := user.GetId()
|
||||
user.Email = dest
|
||||
user.EmailVerified = true
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"email", "email_verified"}, false)
|
||||
columns := []string{"email", "email_verified"}
|
||||
if organization.UseEmailAsUsername {
|
||||
user.Name = user.Email
|
||||
columns = append(columns, "name")
|
||||
}
|
||||
_, err = object.UpdateUser(id, user, columns, false)
|
||||
case object.VerifyTypePhone:
|
||||
user.Phone = dest
|
||||
_, err = object.SetUserField(user, "phone", user.Phone)
|
||||
@@ -449,6 +455,9 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if organization.UseEmailAsUsername {
|
||||
c.SetSessionUsername(user.GetId())
|
||||
}
|
||||
|
||||
err = object.DisableVerificationCode(checkDest)
|
||||
if err != nil {
|
||||
|
@@ -96,15 +96,17 @@ func NewAzureACSEmailProvider(accessKey string, endpoint string) *AzureACSEmailP
|
||||
}
|
||||
}
|
||||
|
||||
func newEmail(fromAddress string, toAddress string, subject string, content string) *Email {
|
||||
func newEmail(fromAddress string, toAddress []string, subject string, content string) *Email {
|
||||
var to []EmailAddress
|
||||
for _, addr := range toAddress {
|
||||
to = append(to, EmailAddress{
|
||||
DisplayName: addr,
|
||||
Address: addr,
|
||||
})
|
||||
}
|
||||
return &Email{
|
||||
Recipients: Recipients{
|
||||
To: []EmailAddress{
|
||||
{
|
||||
DisplayName: toAddress,
|
||||
Address: toAddress,
|
||||
},
|
||||
},
|
||||
To: to,
|
||||
},
|
||||
SenderAddress: fromAddress,
|
||||
Content: Content{
|
||||
@@ -116,7 +118,7 @@ func newEmail(fromAddress string, toAddress string, subject string, content stri
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
|
||||
email := newEmail(fromAddress, toAddress, subject, content)
|
||||
|
||||
postBody, err := json.Marshal(email)
|
||||
|
@@ -48,21 +48,23 @@ func NewHttpEmailProvider(endpoint string, method string, httpHeaders map[string
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
||||
fromNameField := "fromName"
|
||||
toAddressField := "toAddress"
|
||||
toAddressesField := "toAddresses"
|
||||
subjectField := "subject"
|
||||
contentField := "content"
|
||||
|
||||
for k, v := range c.bodyMapping {
|
||||
switch k {
|
||||
case "fromName":
|
||||
fromNameField = v
|
||||
case "toAddress":
|
||||
toAddressField = v
|
||||
case "toAddresses":
|
||||
toAddressesField = v
|
||||
case "subject":
|
||||
subjectField = v
|
||||
case "content":
|
||||
@@ -73,7 +75,6 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
if c.method == "POST" || c.method == "PUT" || c.method == "DELETE" {
|
||||
bodyMap := make(map[string]string)
|
||||
bodyMap[fromNameField] = fromName
|
||||
bodyMap[toAddressField] = toAddress
|
||||
bodyMap[subjectField] = subject
|
||||
bodyMap[contentField] = content
|
||||
|
||||
@@ -89,6 +90,13 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
for k, v := range bodyMap {
|
||||
formValues.Add(k, v)
|
||||
}
|
||||
if len(toAddress) == 1 {
|
||||
formValues.Add(toAddressField, toAddress[0])
|
||||
} else {
|
||||
for _, addr := range toAddress {
|
||||
formValues.Add(toAddressesField, addr)
|
||||
}
|
||||
}
|
||||
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
|
||||
}
|
||||
|
||||
@@ -105,7 +113,13 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Add(fromNameField, fromName)
|
||||
q.Add(toAddressField, toAddress)
|
||||
if len(toAddress) == 1 {
|
||||
q.Add(toAddressField, toAddress[0])
|
||||
} else {
|
||||
for _, addr := range toAddress {
|
||||
q.Add(toAddressesField, addr)
|
||||
}
|
||||
}
|
||||
q.Add(subjectField, subject)
|
||||
q.Add(contentField, content)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
@@ -15,7 +15,7 @@
|
||||
package email
|
||||
|
||||
type EmailProvider interface {
|
||||
Send(fromAddress string, fromName, toAddress string, subject string, content string) error
|
||||
Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error
|
||||
}
|
||||
|
||||
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string) EmailProvider {
|
||||
|
@@ -41,13 +41,22 @@ func NewSendgridEmailProvider(apiKey string, host string, endpoint string) *Send
|
||||
return &SendgridEmailProvider{ApiKey: apiKey, Host: host, Endpoint: endpoint}
|
||||
}
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
client := s.initSendgridClient()
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
|
||||
from := mail.NewEmail(fromName, fromAddress)
|
||||
to := mail.NewEmail("", toAddress)
|
||||
message := mail.NewSingleEmail(from, subject, to, "", content)
|
||||
message := mail.NewV3Mail()
|
||||
message.SetFrom(from)
|
||||
message.AddContent(mail.NewContent("text/html", content))
|
||||
|
||||
personalization := mail.NewPersonalization()
|
||||
|
||||
for _, toAddress := range toAddresses {
|
||||
to := mail.NewEmail(toAddress, toAddress)
|
||||
personalization.AddTos(to)
|
||||
}
|
||||
|
||||
message.AddPersonalizations(personalization)
|
||||
|
||||
client := s.initSendgridClient()
|
||||
resp, err := client.Send(message)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -44,11 +44,15 @@ func NewSmtpEmailProvider(userName string, password string, host string, port in
|
||||
return &SmtpEmailProvider{Dialer: dialer}
|
||||
}
|
||||
|
||||
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
|
||||
message := gomail.NewMessage()
|
||||
|
||||
message.SetAddressHeader("From", fromAddress, fromName)
|
||||
message.SetHeader("To", toAddress)
|
||||
var addresses []string
|
||||
for _, address := range toAddresses {
|
||||
addresses = append(addresses, message.FormatAddress(address, ""))
|
||||
}
|
||||
message.SetHeader("To", addresses...)
|
||||
message.SetHeader("Subject", subject)
|
||||
message.SetBody("text/html", content)
|
||||
|
||||
|
@@ -47,7 +47,7 @@ func (form *VerificationForm) CheckParameter(checkType int, lang string) string
|
||||
return i18n.Translate(lang, "general:Missing parameter") + ": dest."
|
||||
}
|
||||
if form.CaptchaType == "" {
|
||||
return i18n.Translate(lang, "general:Missing parameter") + ": checkType."
|
||||
return i18n.Translate(lang, "general:Missing parameter") + ": captchaType."
|
||||
}
|
||||
if !strings.Contains(form.ApplicationId, "/") {
|
||||
return i18n.Translate(lang, "verification:Wrong parameter") + ": applicationId."
|
||||
|
1
go.mod
1
go.mod
@@ -52,7 +52,6 @@ require (
|
||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stripe/stripe-go/v74 v74.29.0
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
|
2
go.sum
2
go.sum
@@ -872,8 +872,6 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88=
|
||||
github.com/slack-go/slack v0.12.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
|
@@ -47,6 +47,7 @@ func TestGenerateI18nFrontend(t *testing.T) {
|
||||
applyToOtherLanguage("frontend", "fa", data)
|
||||
applyToOtherLanguage("frontend", "cs", data)
|
||||
applyToOtherLanguage("frontend", "sk", data)
|
||||
applyToOtherLanguage("frontend", "az", data)
|
||||
}
|
||||
|
||||
func TestGenerateI18nBackend(t *testing.T) {
|
||||
@@ -77,4 +78,5 @@ func TestGenerateI18nBackend(t *testing.T) {
|
||||
applyToOtherLanguage("backend", "fa", data)
|
||||
applyToOtherLanguage("backend", "cs", data)
|
||||
applyToOtherLanguage("backend", "sk", data)
|
||||
applyToOtherLanguage("backend", "az", data)
|
||||
}
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "فشل تسجيل الدخول: %s",
|
||||
"Invalid token": "الرمز غير صالح",
|
||||
"State expected: %s, but got: %s": "كان من المتوقع الحالة: %s، لكن حصلنا على: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد عبر %%s، يرجى استخدام طريقة أخرى للتسجيل",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد عبر %s، يرجى استخدام طريقة أخرى للتسجيل",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد، يرجى الاتصال بدعم تكنولوجيا المعلومات",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) مرتبط بالفعل بحساب آخر: %s (%s)",
|
||||
"The application: %s does not exist": "التطبيق: %s غير موجود",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام LDAP غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with SMS is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام الرسائل النصية غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with email is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام البريد الإلكتروني غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with face is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام الوجه غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with password is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام كلمة المرور غير مفعّلة لهذا التطبيق",
|
||||
"The organization: %s does not exist": "المنظمة: %s غير موجودة",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "المزود: %s غير موجود",
|
||||
"The provider: %s is not enabled for the application": "المزود: %s غير مفعّل لهذا التطبيق",
|
||||
"Unauthorized operation": "عملية غير مصرح بها",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "هذه العملية غير مسموح بها في وضع العرض التوضيحي",
|
||||
"this operation requires administrator to perform": "هذه العملية تتطلب مسؤولاً لتنفيذها"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "خادم LDAP موجود"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "تم تمكين MFA للبريد الإلكتروني لكن البريد الإلكتروني فارغ",
|
||||
"MFA phone is enabled but phone number is empty": "تم تمكين MFA للهاتف لكن رقم الهاتف فارغ",
|
||||
"New password cannot contain blank space.": "كلمة المرور الجديدة لا يمكن أن تحتوي على مسافات.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "مالك المستخدم واسمه لا يجب أن يكونا فارغين"
|
||||
},
|
||||
"util": {
|
||||
|
197
i18n/locales/az/data.json
Normal file
197
i18n/locales/az/data.json
Normal file
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"account": {
|
||||
"Failed to add user": "İstifadəçi əlavə etmə uğursuz oldu",
|
||||
"Get init score failed, error: %w": "Başlanğıc xal alınması uğursuz oldu, xəta: %w",
|
||||
"Please sign out first": "Xahiş edirik əvvəlcə çıxış edin",
|
||||
"The application does not allow to sign up new account": "Tətbiq yeni hesab qeydiyyatına icazə vermir"
|
||||
},
|
||||
"auth": {
|
||||
"Challenge method should be S256": "Çağırış metodu S256 olmalıdır",
|
||||
"DeviceCode Invalid": "Cihaz Kodu Etibarsızdır",
|
||||
"Failed to create user, user information is invalid: %s": "İstifadəçi yaratma uğursuz oldu, istifadəçi məlumatları etibarsızdır: %s",
|
||||
"Failed to login in: %s": "Giriş uğursuz oldu: %s",
|
||||
"Invalid token": "Etibarsız token",
|
||||
"State expected: %s, but got: %s": "Gözlənilən vəziyyət: %s, lakin alınan: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) mövcud deyil və %s vasitəsilə yeni hesab olaraq qeydiyyatdan keçməyə icazə verilmir, xahiş edirik qeydiyyat üçün başqa üsul istifadə edin",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) mövcud deyil və yeni hesab olaraq qeydiyyatdan keçməyə icazə verilmir, xahiş edirik IT dəstəyinizlə əlaqə saxlayın",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) artıq başqa hesabla əlaqələndirilmişdir: %s (%s)",
|
||||
"The application: %s does not exist": "Tətbiq: %s mövcud deyil",
|
||||
"The application: %s has disabled users to signin": "Tətbiq: %s istifadəçilərin girişini söndürmüşdür",
|
||||
"The login method: login with LDAP is not enabled for the application": "Giriş metodu: LDAP ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with SMS is not enabled for the application": "Giriş metodu: SMS ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with email is not enabled for the application": "Giriş metodu: email ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with face is not enabled for the application": "Giriş metodu: üz ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with password is not enabled for the application": "Giriş metodu: şifrə ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The organization: %s does not exist": "Təşkilat: %s mövcud deyil",
|
||||
"The organization: %s has disabled users to signin": "Təşkilat: %s istifadəçilərin girişini söndürmüşdür",
|
||||
"The provider: %s does not exist": "Provayder: %s mövcud deyil",
|
||||
"The provider: %s is not enabled for the application": "Provayder: %s bu tətbiq üçün aktiv deyil",
|
||||
"Unauthorized operation": "İcazəsiz əməliyyat",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Naməlum təsdiq növü (şifrə və ya provayder deyil), forma = %s",
|
||||
"User's tag: %s is not listed in the application's tags": "İstifadəçinin teqi: %s tətbiqin teqləri siyahısında yoxdur",
|
||||
"UserCode Expired": "İstifadəçi Kodunun Vaxtı Keçib",
|
||||
"UserCode Invalid": "İstifadəçi Kodu Etibarsızdır",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "ödənişli istifadəçi %s aktiv və ya gözləyən abunəyə malik deyil və tətbiq: %s defolt qiymətləndirməyə malik deyil",
|
||||
"the application for user %s is not found": "istifadəçi %s üçün tətbiq tapılmadı",
|
||||
"the organization: %s is not found": "təşkilat: %s tapılmadı"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Xidmət %s və %s uyğun gəlmir"
|
||||
},
|
||||
"check": {
|
||||
"%s does not meet the CIDR format requirements: %s": "%s CIDR format tələblərinə cavab vermir: %s",
|
||||
"Affiliation cannot be blank": "Mənsub sahəsi boş ola bilməz",
|
||||
"CIDR for IP: %s should not be empty": "IP üçün CIDR: %s boş olmamalıdır",
|
||||
"Default code does not match the code's matching rules": "Defolt kod kodun uyğunluq qaydalara uyğun gəlmir",
|
||||
"DisplayName cannot be blank": "Göstərilən Ad boş ola bilməz",
|
||||
"DisplayName is not valid real name": "Göstərilən Ad etibarlı həqiqi ad deyil",
|
||||
"Email already exists": "Email artıq mövcuddur",
|
||||
"Email cannot be empty": "Email boş ola bilməz",
|
||||
"Email is invalid": "Email etibarsızdır",
|
||||
"Empty username.": "Boş istifadəçi adı.",
|
||||
"Face data does not exist, cannot log in": "Üz məlumatları mövcud deyil, giriş edilə bilməz",
|
||||
"Face data mismatch": "Üz məlumatları uyğun gəlmir",
|
||||
"Failed to parse client IP: %s": "Müştəri IP-ni təhlil etmək uğursuz oldu: %s",
|
||||
"FirstName cannot be blank": "Ad boş ola bilməz",
|
||||
"Invitation code cannot be blank": "Dəvət kodu boş ola bilməz",
|
||||
"Invitation code exhausted": "Dəvət kodu tükənib",
|
||||
"Invitation code is invalid": "Dəvət kodu etibarsızdır",
|
||||
"Invitation code suspended": "Dəvət kodu dayandırılıb",
|
||||
"LDAP user name or password incorrect": "LDAP istifadəçi adı və ya şifrə yanlışdır",
|
||||
"LastName cannot be blank": "Soyad boş ola bilməz",
|
||||
"Multiple accounts with same uid, please check your ldap server": "Eyni uid ilə çoxlu hesablar, xahiş edirik ldap serverinizi yoxlayın",
|
||||
"Organization does not exist": "Təşkilat mövcud deyil",
|
||||
"Password cannot be empty": "Şifrə boş ola bilməz",
|
||||
"Phone already exists": "Telefon artıq mövcuddur",
|
||||
"Phone cannot be empty": "Telefon boş ola bilməz",
|
||||
"Phone number is invalid": "Telefon nömrəsi etibarsızdır",
|
||||
"Please register using the email corresponding to the invitation code": "Xahiş edirik dəvət koduna uyğun email istifadə edərək qeydiyyatdan keçin",
|
||||
"Please register using the phone corresponding to the invitation code": "Xahiş edirik dəvət koduna uyğun telefon istifadə edərək qeydiyyatdan keçin",
|
||||
"Please register using the username corresponding to the invitation code": "Xahiş edirik dəvət koduna uyğun istifadəçi adı istifadə edərək qeydiyyatdan keçin",
|
||||
"Session outdated, please login again": "Sessiyanın vaxtı keçib, xahiş edirik yenidən daxil olun",
|
||||
"The invitation code has already been used": "Dəvət kodu artıq istifadə edilib",
|
||||
"The user is forbidden to sign in, please contact the administrator": "İstifadəçinin girişi qadağandır, xahiş edirik administratorla əlaqə saxlayın",
|
||||
"The user: %s doesn't exist in LDAP server": "İstifadəçi: %s LDAP serverində mövcud deyil",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "İstifadəçi adı yalnız hərf-rəqəm simvolları, alt xətt və ya defis ehtiva edə bilər, ardıcıl defis və ya alt xətt ola bilməz və defis və ya alt xəttlə başlaya və ya bitə bilməz.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Hesab sahəsi \\\"%s\\\" üçün dəyər \\\"%s\\\" hesab elementi regex-inə uyğun gəlmir",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Qeydiyyat sahəsi \\\"%s\\\" üçün dəyər \\\"%s\\\" tətbiq \\\"%s\\\"in qeydiyyat elementi regex-inə uyğun gəlmir",
|
||||
"Username already exists": "İstifadəçi adı artıq mövcuddur",
|
||||
"Username cannot be an email address": "İstifadəçi adı email ünvanı ola bilməz",
|
||||
"Username cannot contain white spaces": "İstifadəçi adı boşluqlar ehtiva edə bilməz",
|
||||
"Username cannot start with a digit": "İstifadəçi adı rəqəmlə başlaya bilməz",
|
||||
"Username is too long (maximum is 255 characters).": "İstifadəçi adı çox uzundur (maksimum 255 simvoldur).",
|
||||
"Username must have at least 2 characters": "İstifadəçi adı ən azı 2 simvola malik olmalıdır",
|
||||
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "İstifadəçi adı email formatını dəstəkləyir. Həmçinin istifadəçi adı yalnız hərf-rəqəm simvolları, alt xətt və ya defis ehtiva edə bilər, ardıcıl defis və ya alt xətt ola bilməz və defis və ya alt xəttlə başlaya və ya bitə bilməz. Həmçinin email formatına diqqət edin.",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Yanlış şifrə və ya kod dəfələrlə daxil etmisiniz, xahiş edirik %d dəqiqə gözləyin və yenidən cəhd edin",
|
||||
"Your IP address: %s has been banned according to the configuration of: ": "IP ünvanınız: %s konfiqurasiyaya görə qadağan edilib: ",
|
||||
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Şifrənizin vaxtı keçib. Xahiş edirik \\\"Şifrəni unutdum\\\" düyməsinə basaraq şifrənizi sıfırlayın",
|
||||
"Your region is not allow to signup by phone": "Regionunuzda telefonla qeydiyyata icazə verilmir",
|
||||
"password or code is incorrect": "şifrə və ya kod yanlışdır",
|
||||
"password or code is incorrect, you have %s remaining chances": "şifrə və ya kod yanlışdır, %s şansınız qalıb",
|
||||
"unsupported password type: %s": "dəstəklənməyən şifrə növü: %s"
|
||||
},
|
||||
"enforcer": {
|
||||
"the adapter: %s is not found": "adapter: %s tapılmadı"
|
||||
},
|
||||
"general": {
|
||||
"Failed to import groups": "Qrupları idxal etmək uğursuz oldu",
|
||||
"Failed to import users": "İstifadəçiləri idxal etmək uğursuz oldu",
|
||||
"Missing parameter": "Parametr çatışmır",
|
||||
"Only admin user can specify user": "Yalnız admin istifadəçi başqa istifadəçini təyin edə bilər",
|
||||
"Please login first": "Xahiş edirik əvvəlcə daxil olun",
|
||||
"The organization: %s should have one application at least": "Təşkilat: %s ən azı bir tətbiqə malik olmalıdır",
|
||||
"The user: %s doesn't exist": "İstifadəçi: %s mövcud deyil",
|
||||
"Wrong userId": "Yanlış istifadəçi ID-si",
|
||||
"don't support captchaProvider: ": "captcha provayderini dəstəkləmir: ",
|
||||
"this operation is not allowed in demo mode": "bu əməliyyat demo rejimində icazə verilmir",
|
||||
"this operation requires administrator to perform": "bu əməliyyat administrator tərəfindən yerinə yetirilməsini tələb edir"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP serveri mövcuddur"
|
||||
},
|
||||
"link": {
|
||||
"Please link first": "Xahiş edirik əvvəlcə əlaqələndirin",
|
||||
"This application has no providers": "Bu tətbiqin provayderləri yoxdur",
|
||||
"This application has no providers of type": "Bu tətbiqin bu növdə provayderi yoxdur",
|
||||
"This provider can't be unlinked": "Bu provayderin əlaqəsi kəsilə bilməz",
|
||||
"You are not the global admin, you can't unlink other users": "Siz qlobal admin deyilsiniz, digər istifadəçilərin əlaqəsini kəsə bilməzsiniz",
|
||||
"You can't unlink yourself, you are not a member of any application": "Öz əlaqənizi kəsə bilməzsiniz, heç bir tətbiqin üzvü deyilsiniz"
|
||||
},
|
||||
"organization": {
|
||||
"Only admin can modify the %s.": "Yalnız admin %s-ni dəyişdirə bilər.",
|
||||
"The %s is immutable.": "%s dəyişilməzdir.",
|
||||
"Unknown modify rule %s.": "Naməlum dəyişdirmə qaydası %s.",
|
||||
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "'built-in' təşkilatına yeni istifadəçi əlavə etmək hazırda söndürülüb. Qeyd edin: 'built-in' təşkilatındakı bütün istifadəçilər Casdoor-da qlobal administratorlardır. Sənədlərə baxın: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Əgər hələ də 'built-in' təşkilat üçün istifadəçi yaratmaq istəyirsinizsə, təşkilatın tənzimləmələr səhifəsinə gedib 'İmtiyaz razılığına malikdir' seçimini aktiv edin."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "İcazə: \\\"%s\\\" mövcud deyil"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Etibarsız tətbiq id-si",
|
||||
"the provider: %s does not exist": "provayder: %s mövcud deyil"
|
||||
},
|
||||
"resource": {
|
||||
"User is nil for tag: avatar": "Avatar teqi üçün istifadəçi nil-dir",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "İstifadəçi adı və ya tam fayl yolu boşdur: istifadəçi adı = %s, tam fayl yolu = %s"
|
||||
},
|
||||
"saml": {
|
||||
"Application %s not found": "Tətbiq %s tapılmadı"
|
||||
},
|
||||
"saml_sp": {
|
||||
"provider %s's category is not SAML": "provayder %s-in kateqoriyası SAML deyil"
|
||||
},
|
||||
"service": {
|
||||
"Empty parameters for emailForm: %v": "emailForm üçün boş parametrlər: %v",
|
||||
"Invalid Email receivers: %s": "Etibarsız Email qəbuledicilər: %s",
|
||||
"Invalid phone receivers: %s": "Etibarsız telefon qəbuledicilər: %s"
|
||||
},
|
||||
"storage": {
|
||||
"The objectKey: %s is not allowed": "obyekt açarı: %s icazə verilmir",
|
||||
"The provider type: %s is not supported": "provayder növü: %s dəstəklənmir"
|
||||
},
|
||||
"subscription": {
|
||||
"Error": "Xəta"
|
||||
},
|
||||
"token": {
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s bu tətbiqdə dəstəklənmir",
|
||||
"Invalid application or wrong clientSecret": "Etibarsız tətbiq və ya yanlış müştəri sirri",
|
||||
"Invalid client_id": "Etibarsız client_id",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Yönləndirmə URI: %s icazə verilən Yönləndirmə URI siyahısında mövcud deyil",
|
||||
"Token not found, invalid accessToken": "Token tapılmadı, etibarsız accessToken"
|
||||
},
|
||||
"user": {
|
||||
"Display name cannot be empty": "Göstərilən ad boş ola bilməz",
|
||||
"MFA email is enabled but email is empty": "MFA email aktiv edilib, lakin email boşdur",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon aktiv edilib, lakin telefon nömrəsi boşdur",
|
||||
"New password cannot contain blank space.": "Yeni şifrə boş yer ehtiva edə bilməz.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "istifadəçinin sahibi və adı boş olmamalıdır"
|
||||
},
|
||||
"util": {
|
||||
"No application is found for userId: %s": "İstifadəçi ID-si üçün heç bir tətbiq tapılmadı: %s",
|
||||
"No provider for category: %s is found for application: %s": "Tətbiq üçün kateqoriya üçün heç bir provayder tapılmadı: %s: %s",
|
||||
"The provider: %s is not found": "Provayder: %s tapılmadı"
|
||||
},
|
||||
"verification": {
|
||||
"Invalid captcha provider.": "Etibarsız captcha provaydeři.",
|
||||
"Phone number is invalid in your region %s": "Telefon nömrəsi sizin regionunuzda etibarsızdır %s",
|
||||
"The verification code has already been used!": "Doğrulama kodu artıq istifadə edilib!",
|
||||
"The verification code has not been sent yet!": "Doğrulama kodu hələ göndərilməyib!",
|
||||
"Turing test failed.": "Türinq testi uğursuz oldu.",
|
||||
"Unable to get the email modify rule.": "Email dəyişdirmə qaydasını əldə etmək mümkün olmadı.",
|
||||
"Unable to get the phone modify rule.": "Telefon dəyişdirmə qaydasını əldə etmək mümkün olmadı.",
|
||||
"Unknown type": "Naməlum növ",
|
||||
"Wrong verification code!": "Yanlış doğrulama kodu!",
|
||||
"You should verify your code in %d min!": "Kodunuzu %d dəqiqə içində doğrulamalısınız!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "xahiş edirik tətbiq üçün \\\"Provaydeerlər\\\" siyahısına SMS provaydeři əlavə edin: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "xahiş edirik tətbiq üçün \\\"Provaydeerlər\\\" siyahısına Email provaydeři əlavə edin: %s",
|
||||
"the user does not exist, please sign up first": "istifadəçi mövcud deyil, xahiş edirik əvvəlcə qeydiyyatdan keçin"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Bu istifadəçi üçün heç bir etimadnamə tapılmadı",
|
||||
"Please call WebAuthnSigninBegin first": "Xahiş edirik əvvəlcə WebAuthnSigninBegin çağırın"
|
||||
}
|
||||
}
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Nepodařilo se přihlásit: %s",
|
||||
"Invalid token": "Neplatný token",
|
||||
"State expected: %s, but got: %s": "Očekávaný stav: %s, ale získán: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %%s, prosím použijte jiný způsob registrace",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %s, prosím použijte jiný způsob registrace",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet, prosím kontaktujte svou IT podporu",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) je již propojen s jiným účtem: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikace: %s neexistuje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí LDAP není pro aplikaci povolena",
|
||||
"The login method: login with SMS is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí SMS není pro aplikaci povolena",
|
||||
"The login method: login with email is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí e-mailu není pro aplikaci povolena",
|
||||
"The login method: login with face is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí obličeje není pro aplikaci povolena",
|
||||
"The login method: login with password is not enabled for the application": "Metoda přihlášení: přihlášení pomocí hesla není pro aplikaci povolena",
|
||||
"The organization: %s does not exist": "Organizace: %s neexistuje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Poskytovatel: %s neexistuje",
|
||||
"The provider: %s is not enabled for the application": "Poskytovatel: %s není pro aplikaci povolen",
|
||||
"Unauthorized operation": "Neoprávněná operace",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "tato operace není povolena v demo režimu",
|
||||
"this operation requires administrator to perform": "tato operace vyžaduje administrátora k provedení"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Ldap server existuje"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-mail je povolen, ale e-mail je prázdný",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon je povolen, ale telefonní číslo je prázdné",
|
||||
"New password cannot contain blank space.": "Nové heslo nemůže obsahovat prázdné místo.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "vlastník a jméno uživatele by neměly být prázdné"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Konnte nicht anmelden: %s",
|
||||
"Invalid token": "Ungültiges Token",
|
||||
"State expected: %s, but got: %s": "Erwarteter Zustand: %s, aber erhalten: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %%s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
|
||||
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Die Anmeldemethode: Anmeldung mit LDAP ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with SMS is not enabled for the application": "Die Anmeldemethode: Anmeldung per SMS ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with email is not enabled for the application": "Die Anmeldemethode: Anmeldung per E-Mail ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with face is not enabled for the application": "Die Anmeldemethode: Anmeldung per Gesicht ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
|
||||
"The organization: %s does not exist": "Die Organisation: %s existiert nicht",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Der Anbieter: %s existiert nicht",
|
||||
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
|
||||
"Unauthorized operation": "Nicht autorisierte Operation",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "Dieser Vorgang ist im Demo-Modus nicht erlaubt",
|
||||
"this operation requires administrator to perform": "Dieser Vorgang erfordert einen Administrator zur Ausführung"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Es gibt einen LDAP-Server"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-E-Mail ist aktiviert, aber E-Mail ist leer",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-Telefon ist aktiviert, aber Telefonnummer ist leer",
|
||||
"New password cannot contain blank space.": "Das neue Passwort darf keine Leerzeichen enthalten.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "Eigentümer und Name des Benutzers dürfen nicht leer sein"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Failed to login in: %s",
|
||||
"Invalid token": "Invalid token",
|
||||
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||
"The application: %s does not exist": "The application: %s does not exist",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "The provider: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
|
||||
"this operation requires administrator to perform": "this operation requires administrator to perform"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Ldap server exist"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
|
||||
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
|
||||
"New password cannot contain blank space.": "New password cannot contain blank space.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "No se ha podido iniciar sesión en: %s",
|
||||
"Invalid token": "Token inválido",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, pero se obtuvo: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %%s, por favor use otro método para registrarse",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %s, por favor use otro método para registrarse",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
|
||||
"The application: %s does not exist": "La aplicación: %s no existe",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "El método de inicio de sesión: inicio de sesión con LDAP no está habilitado para la aplicación",
|
||||
"The login method: login with SMS is not enabled for the application": "El método de inicio de sesión: inicio de sesión con SMS no está habilitado para la aplicación",
|
||||
"The login method: login with email is not enabled for the application": "El método de inicio de sesión: inicio de sesión con correo electrónico no está habilitado para la aplicación",
|
||||
"The login method: login with face is not enabled for the application": "El método de inicio de sesión: inicio de sesión con reconocimiento facial no está habilitado para la aplicación",
|
||||
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
|
||||
"The organization: %s does not exist": "La organización: %s no existe",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "El proveedor: %s no existe",
|
||||
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
|
||||
"Unauthorized operation": "Operación no autorizada",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "esta operación no está permitida en modo de demostración",
|
||||
"this operation requires administrator to perform": "esta operación requiere que el administrador la realice"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "El servidor LDAP existe"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "El correo electrónico MFA está habilitado pero el correo está vacío",
|
||||
"MFA phone is enabled but phone number is empty": "El teléfono MFA está habilitado pero el número de teléfono está vacío",
|
||||
"New password cannot contain blank space.": "La nueva contraseña no puede contener espacios en blanco.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "el propietario y el nombre del usuario no deben estar vacíos"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "عدم موفقیت در ورود: %s",
|
||||
"Invalid token": "توکن نامعتبر",
|
||||
"State expected: %s, but got: %s": "وضعیت مورد انتظار: %s، اما دریافت شد: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید از طریق %%s نیست، لطفاً از روش دیگری برای ثبتنام استفاده کنید",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید از طریق %s نیست، لطفاً از روش دیگری برای ثبتنام استفاده کنید",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید نیست، لطفاً با پشتیبانی IT خود تماس بگیرید",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)",
|
||||
"The application: %s does not exist": "برنامه: %s وجود ندارد",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست",
|
||||
"The login method: login with SMS is not enabled for the application": "روش ورود: ورود با پیامک برای برنامه فعال نیست",
|
||||
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست",
|
||||
"The login method: login with face is not enabled for the application": "روش ورود: ورود با چهره برای برنامه فعال نیست",
|
||||
"The login method: login with password is not enabled for the application": "روش ورود: ورود با رمز عبور برای برنامه فعال نیست",
|
||||
"The organization: %s does not exist": "سازمان: %s وجود ندارد",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "ارائهکننده: %s وجود ندارد",
|
||||
"The provider: %s is not enabled for the application": "ارائهدهنده: %s برای برنامه فعال نیست",
|
||||
"Unauthorized operation": "عملیات غیرمجاز",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست",
|
||||
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "سرور LDAP وجود دارد"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "ایمیل MFA فعال است اما ایمیل خالی است",
|
||||
"MFA phone is enabled but phone number is empty": "تلفن MFA فعال است اما شماره تلفن خالی است",
|
||||
"New password cannot contain blank space.": "رمز عبور جدید نمیتواند حاوی فاصله خالی باشد.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "مالک و نام کاربر نباید خالی باشند"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Sisäänkirjautuminen epäonnistui: %s",
|
||||
"Invalid token": "Virheellinen token",
|
||||
"State expected: %s, but got: %s": "Odotettiin tilaa: %s, mutta saatiin: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä kautta %%s, käytä toista tapaa rekisteröityä",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä kautta %s, käytä toista tapaa rekisteröityä",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä, ota yhteyttä IT-tukeen",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tili providerille: %s ja käyttäjälle: %s (%s) on jo linkitetty toiseen tiliin: %s (%s)",
|
||||
"The application: %s does not exist": "Sovellus: %s ei ole olemassa",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Kirjautumistapa: kirjautuminen LDAP:n kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with SMS is not enabled for the application": "Kirjautumistapa: kirjautuminen SMS:n kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with email is not enabled for the application": "Kirjautumistapa: kirjautuminen sähköpostin kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with face is not enabled for the application": "Kirjautumistapa: kirjautuminen kasvotunnistuksella ei ole käytössä sovelluksessa",
|
||||
"The login method: login with password is not enabled for the application": "Kirjautumistapa: kirjautuminen salasanalla ei ole käytössä sovelluksessa",
|
||||
"The organization: %s does not exist": "Organisaatio: %s ei ole olemassa",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Provider: %s ei ole olemassa",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s ei ole käytössä sovelluksessa",
|
||||
"Unauthorized operation": "Luvaton toiminto",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "tämä toiminto ei ole sallittu demo-tilassa",
|
||||
"this operation requires administrator to perform": "tämä toiminto vaatii ylläpitäjän suorittamista"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-palvelin on olemassa"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-sähköposti on käytössä, mutta sähköposti on tyhjä",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-puhelin on käytössä, mutta puhelinnumero on tyhjä",
|
||||
"New password cannot contain blank space.": "Uusi salasana ei voi sisältää välilyöntejä.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "käyttäjän omistaja ja nimi eivät saa olla tyhjiä"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Échec de la connexion : %s",
|
||||
"Invalid token": "Jeton invalide",
|
||||
"State expected: %s, but got: %s": "État attendu : %s, mais obtenu : %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %%s, veuillez utiliser une autre méthode pour vous inscrire",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %s, veuillez utiliser une autre méthode pour vous inscrire",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
|
||||
"The application: %s does not exist": "L'application : %s n'existe pas",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "La méthode de connexion : connexion LDAP n'est pas activée pour l'application",
|
||||
"The login method: login with SMS is not enabled for the application": "La méthode de connexion : connexion par SMS n'est pas activée pour l'application",
|
||||
"The login method: login with email is not enabled for the application": "La méthode de connexion : connexion par e-mail n'est pas activée pour l'application",
|
||||
"The login method: login with face is not enabled for the application": "La méthode de connexion : connexion par visage n'est pas activée pour l'application",
|
||||
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
|
||||
"The organization: %s does not exist": "L'organisation : %s n'existe pas",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Le fournisseur : %s n'existe pas",
|
||||
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
|
||||
"Unauthorized operation": "Opération non autorisée",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "cette opération n'est pas autorisée en mode démo",
|
||||
"this operation requires administrator to perform": "cette opération nécessite un administrateur pour être effectuée"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Le serveur LDAP existe"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "L'authentification MFA par e-mail est activée mais l'e-mail est vide",
|
||||
"MFA phone is enabled but phone number is empty": "L'authentification MFA par téléphone est activée mais le numéro de téléphone est vide",
|
||||
"New password cannot contain blank space.": "Le nouveau mot de passe ne peut pas contenir d'espace.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "le propriétaire et le nom de l'utilisateur ne doivent pas être vides"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "כניסה נכשלה: %s",
|
||||
"Invalid token": "אסימון שגוי",
|
||||
"State expected: %s, but got: %s": "מצב צפוי: %s, אך התקבל: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש דרך %%s, אנא השתמש בדרך אחרת להרשמה",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש דרך %s, אנא השתמש בדרך אחרת להרשמה",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש, אנא צור קשר עם התמיכה הטכנית",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "החשבון עבור ספק: %s ושם משתמש: %s (%s) כבר מקושר לחשבון אחר: %s (%s)",
|
||||
"The application: %s does not exist": "האפליקציה: %s אינה קיימת",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "שיטת הכניסה: כניסה עם LDAP אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with SMS is not enabled for the application": "שיטת הכניסה: כניסה עם SMS אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with email is not enabled for the application": "שיטת הכניסה: כניסה עם אימייל אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with face is not enabled for the application": "שיטת הכניסה: כניסה עם פנים אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with password is not enabled for the application": "שיטת הכניסה: כניסה עם סיסמה אינה מאופשרת לאפליקציה",
|
||||
"The organization: %s does not exist": "הארגון: %s אינו קיים",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "הספק: %s אינו קיים",
|
||||
"The provider: %s is not enabled for the application": "הספק: %s אינו מאופשר לאפליקציה",
|
||||
"Unauthorized operation": "פעולה לא מורשית",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "פעולה זו אינה מותרת במצב הדגמה",
|
||||
"this operation requires administrator to perform": "פעולה זו דורשת מנהל לביצוע"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "שרת LDAP קיים"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA דוא\"ל מופעל אך הדוא\"ל ריק",
|
||||
"MFA phone is enabled but phone number is empty": "MFA טלפון מופעל אך מספר הטלפון ריק",
|
||||
"New password cannot contain blank space.": "הסיסמה החדשה אינה יכולה להכיל רווחים.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "הבעלים והשם של המשתמש אינם יכולים להיות ריקים"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Gagal masuk: %s",
|
||||
"Invalid token": "Token tidak valid",
|
||||
"State expected: %s, but got: %s": "Diharapkan: %s, tapi diperoleh: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %%s, silakan gunakan cara lain untuk mendaftar",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %s, silakan gunakan cara lain untuk mendaftar",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk penyedia: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikasi: %s tidak ada",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metode masuk: masuk dengan LDAP tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with SMS is not enabled for the application": "Metode masuk: masuk dengan SMS tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with email is not enabled for the application": "Metode masuk: masuk dengan email tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with face is not enabled for the application": "Metode masuk: masuk dengan wajah tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with password is not enabled for the application": "Metode login: login dengan sandi tidak diaktifkan untuk aplikasi tersebut",
|
||||
"The organization: %s does not exist": "Organisasi: %s tidak ada",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Penyedia: %s tidak ada",
|
||||
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
|
||||
"Unauthorized operation": "Operasi tidak sah",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "operasi ini tidak diizinkan dalam mode demo",
|
||||
"this operation requires administrator to perform": "operasi ini memerlukan administrator untuk melakukannya"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Server ldap ada"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "Email MFA diaktifkan tetapi email kosong",
|
||||
"MFA phone is enabled but phone number is empty": "Telepon MFA diaktifkan tetapi nomor telepon kosong",
|
||||
"New password cannot contain blank space.": "Sandi baru tidak boleh mengandung spasi kosong.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "pemilik dan nama pengguna tidak boleh kosong"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Login fallito: %s",
|
||||
"Invalid token": "Token non valido",
|
||||
"State expected: %s, but got: %s": "Stato atteso: %s, ricevuto: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Account per provider: %s e utente: %s (%s) non esiste, registrazione tramite %%s non consentita",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Account per provider: %s e utente: %s (%s) non esiste, registrazione tramite %s non consentita",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Account per provider: %s e utente: %s (%s) non esiste, registrazione non consentita: contatta l'assistenza IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account per provider: %s e utente: %s (%s) già collegato a un altro account: %s (%s)",
|
||||
"The application: %s does not exist": "L'app: %s non esiste",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metodo di accesso: login con LDAP non abilitato per l'applicazione",
|
||||
"The login method: login with SMS is not enabled for the application": "Metodo di accesso: login con SMS non abilitato per l'applicazione",
|
||||
"The login method: login with email is not enabled for the application": "Metodo di accesso: login con email non abilitato per l'applicazione",
|
||||
"The login method: login with face is not enabled for the application": "Metodo di accesso: login con riconoscimento facciale non abilitato per l'applicazione",
|
||||
"The login method: login with password is not enabled for the application": "Login con password non abilitato per questa app",
|
||||
"The organization: %s does not exist": "L'organizzazione: %s non esiste",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Il provider: %s non esiste",
|
||||
"The provider: %s is not enabled for the application": "Il provider: %s non è abilitato per l'app",
|
||||
"Unauthorized operation": "Operazione non autorizzata",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "questa operazione non è consentita in modalità demo",
|
||||
"this operation requires administrator to perform": "questa operazione richiede un amministratore"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Server LDAP esistente"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "L'email MFA è abilitata ma l'email è vuota",
|
||||
"MFA phone is enabled but phone number is empty": "Il telefono MFA è abilitato ma il numero di telefono è vuoto",
|
||||
"New password cannot contain blank space.": "Nuova password non può contenere spazi",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "il proprietario e il nome dell'utente non devono essere vuoti"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "ログインできませんでした:%s",
|
||||
"Invalid token": "無効なトークン",
|
||||
"State expected: %s, but got: %s": "期待される状態: %s、実際には:%s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s(%s)が存在せず、新しいアカウントを %%s 経由でサインアップすることはできません。他の方法でサインアップしてください",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s(%s)が存在せず、新しいアカウントを %s 経由でサインアップすることはできません。他の方法でサインアップしてください",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "プロバイダー名:%sとユーザー名:%s(%s)のアカウントは存在しません。新しいアカウントとしてサインアップすることはできません。 ITサポートに連絡してください",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "プロバイダのアカウント:%s とユーザー名:%s (%s) は既に別のアカウント:%s (%s) にリンクされています",
|
||||
"The application: %s does not exist": "アプリケーション: %sは存在しません",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "このアプリケーションでは LDAP ログインは有効になっていません",
|
||||
"The login method: login with SMS is not enabled for the application": "このアプリケーションでは SMS ログインは有効になっていません",
|
||||
"The login method: login with email is not enabled for the application": "このアプリケーションではメールログインは有効になっていません",
|
||||
"The login method: login with face is not enabled for the application": "このアプリケーションでは顔認証ログインは有効になっていません",
|
||||
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
|
||||
"The organization: %s does not exist": "組織「%s」は存在しません",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "プロバイダ「%s」は存在しません",
|
||||
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
|
||||
"Unauthorized operation": "不正操作",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "この操作はデモモードでは許可されていません",
|
||||
"this operation requires administrator to perform": "この操作は管理者権限が必要です"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAPサーバーは存在します"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA メールが有効になっていますが、メールアドレスが空です",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 電話番号が有効になっていますが、電話番号が空です",
|
||||
"New password cannot contain blank space.": "新しいパスワードにはスペースを含めることはできません。",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "ユーザーのオーナーと名前は空にできません"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Inloggen mislukt: %s",
|
||||
"Invalid token": "Ongeldige token",
|
||||
"State expected: %s, but got: %s": "Verwachte state: %s, maar kreeg: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren via %%s, gebruik een andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren via %s, gebruik een andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren, contacteer IT-support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account voor provider: %s en gebruikersnaam: %s (%s) is al gelinkt aan ander account: %s (%s)",
|
||||
"The application: %s does not exist": "Applicatie: %s bestaat niet",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Inloggen via LDAP is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with SMS is not enabled for the application": "Inloggen via SMS is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with email is not enabled for the application": "Inloggen via e-mail is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with face is not enabled for the application": "Inloggen via gezichtsherkenning is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with password is not enabled for the application": "Inloggen via wachtwoord is niet ingeschakeld voor deze applicatie",
|
||||
"The organization: %s does not exist": "Organisatie: %s bestaat niet",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Provider: %s bestaat niet",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s is niet ingeschakeld voor de applicatie",
|
||||
"Unauthorized operation": "Ongeautoriseerde handeling",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "deze handeling is niet toegestaan in demo-modus",
|
||||
"this operation requires administrator to perform": "deze handeling vereist beheerder"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-server bestaat al"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-mail is ingeschakeld maar e-mailadres is leeg",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefoon is ingeschakeld maar telefoonnummer is leeg",
|
||||
"New password cannot contain blank space.": "Nieuw wachtwoord mag geen spaties bevatten.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "eigenaar en naam van gebruiker mogen niet leeg zijn"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "로그인에 실패했습니다.: %s",
|
||||
"Invalid token": "유효하지 않은 토큰",
|
||||
"State expected: %s, but got: %s": "예상한 상태: %s, 실제 상태: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "제공자 계정: %s와 사용자 이름: %s (%s)은(는) 존재하지 않으며 %%s를 통해 새 계정으로 가입하는 것이 허용되지 않습니다. 다른 방법으로 가입하십시오",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "제공자 계정: %s와 사용자 이름: %s (%s)은(는) 존재하지 않으며 %s를 통해 새 계정으로 가입하는 것이 허용되지 않습니다. 다른 방법으로 가입하십시오",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "공급자 계정 %s과 사용자 이름 %s (%s)는 존재하지 않으며 새 계정으로 등록할 수 없습니다. IT 지원팀에 문의하십시오",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "공급자 계정 %s과 사용자 이름 %s(%s)는 이미 다른 계정 %s(%s)에 연결되어 있습니다",
|
||||
"The application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "LDAP를 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with SMS is not enabled for the application": "SMS를 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with email is not enabled for the application": "이메일을 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with face is not enabled for the application": "얼굴 인식을 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
|
||||
"The organization: %s does not exist": "조직 %s이(가) 존재하지 않습니다",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "제공자 %s이(가) 존재하지 않습니다",
|
||||
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
|
||||
"Unauthorized operation": "무단 조작",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "이 작업은 데모 모드에서 허용되지 않습니다",
|
||||
"this operation requires administrator to perform": "이 작업은 관리자 권한이 필요합니다"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP 서버가 존재합니다"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA 이메일이 활성화되었지만 이메일이 비어 있습니다",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 전화번호가 활성화되었지만 전화번호가 비어 있습니다",
|
||||
"New password cannot contain blank space.": "새 비밀번호에는 공백이 포함될 수 없습니다.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "사용자의 소유자와 이름은 비워둘 수 없습니다"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Gagal log masuk: %s",
|
||||
"Invalid token": "Token tidak sah",
|
||||
"State expected: %s, but got: %s": "Jangkaan keadaan: %s, tetapi dapat: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar melalui %%s, sila guna cara lain",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar melalui %s, sila guna cara lain",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar, sila hubungi sokongan IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) sudah dipautkan kepada akaun lain: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikasi: %s tidak wujud",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Kaedah log masuk LDAP tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with SMS is not enabled for the application": "Kaedah log masuk SMS tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with email is not enabled for the application": "Kaedah log masuk emel tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with face is not enabled for the application": "Kaedah log masuk muka tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with password is not enabled for the application": "Kaedah log masuk kata laluan tidak dibenarkan untuk aplikasi ini",
|
||||
"The organization: %s does not exist": "Organisasi: %s tidak wujud",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Pembekal: %s tidak wujud",
|
||||
"The provider: %s is not enabled for the application": "Pembekal: %s tidak dibenarkan untuk aplikasi ini",
|
||||
"Unauthorized operation": "Operasi tidak dibenarkan",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "operasi ini tidak dibenarkan dalam mod demo",
|
||||
"this operation requires administrator to perform": "operasi ini perlukan pentadbir untuk jalankan"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Pelayan LDAP sudah wujud"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA emel dibenarkan tetapi emel kosong",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon dibenarkan tetapi nombor telefon kosong",
|
||||
"New password cannot contain blank space.": "Kata laluan baharu tidak boleh ada ruang kosong.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "pemilik dan nama pengguna tidak boleh kosong"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Inloggen mislukt: %s",
|
||||
"Invalid token": "Ongeldige token",
|
||||
"State expected: %s, but got: %s": "Verwachtte state: %s, gekregen: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Gebruiker bestaat niet; aanmelden via %%s niet toegestaan, kies andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Gebruiker bestaat niet; aanmelden via %s niet toegestaan, kies andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Gebruiker bestaat niet; aanmelden niet toegestaan, neem contact op met IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account al gekoppeld aan andere gebruiker: %s (%s)",
|
||||
"The application: %s does not exist": "Applicatie %s bestaat niet",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "LDAP-login uitgeschakeld voor deze app",
|
||||
"The login method: login with SMS is not enabled for the application": "SMS-login uitgeschakeld voor deze app",
|
||||
"The login method: login with email is not enabled for the application": "E-mail-login uitgeschakeld voor deze app",
|
||||
"The login method: login with face is not enabled for the application": "Face-login uitgeschakeld voor deze app",
|
||||
"The login method: login with password is not enabled for the application": "Wachtwoord-login uitgeschakeld voor deze app",
|
||||
"The organization: %s does not exist": "Organisatie %s bestaat niet",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Provider %s bestaat niet",
|
||||
"The provider: %s is not enabled for the application": "Provider %s uitgeschakeld voor deze app",
|
||||
"Unauthorized operation": "Niet toegestane handeling",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "Handeling niet toegestaan in demo-modus",
|
||||
"this operation requires administrator to perform": "Alleen beheerder kan deze handeling uitvoeren"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-server bestaat al"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-mail ingeschakeld maar e-mailadres leeg",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefoon ingeschakeld maar nummer leeg",
|
||||
"New password cannot contain blank space.": "Nieuw wachtwoord mag geen spaties bevatten",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "Eigenaar en naam van gebruiker mogen niet leeg zijn"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Logowanie nie powiodło się: %s",
|
||||
"Invalid token": "Nieprawidłowy token",
|
||||
"State expected: %s, but got: %s": "Oczekiwano stanu: %s, ale otrzymano: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto przez %%s, użyj innej metody rejestracji",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto przez %s, użyj innej metody rejestracji",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto, skontaktuj się z pomocą IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) jest już powiązane z innym kontem: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikacja: %s nie istnieje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metoda logowania: logowanie przez LDAP nie jest włączone dla aplikacji",
|
||||
"The login method: login with SMS is not enabled for the application": "Metoda logowania: logowanie przez SMS nie jest włączona dla aplikacji",
|
||||
"The login method: login with email is not enabled for the application": "Metoda logowania: logowanie przez email nie jest włączona dla aplikacji",
|
||||
"The login method: login with face is not enabled for the application": "Metoda logowania: logowanie przez twarz nie jest włączona dla aplikacji",
|
||||
"The login method: login with password is not enabled for the application": "Metoda logowania: logowanie przez hasło nie jest włączone dla aplikacji",
|
||||
"The organization: %s does not exist": "Organizacja: %s nie istnieje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Dostawca: %s nie istnieje",
|
||||
"The provider: %s is not enabled for the application": "Dostawca: %s nie jest włączony dla aplikacji",
|
||||
"Unauthorized operation": "Nieautoryzowana operacja",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "ta operacja nie jest dozwolona w trybie demo",
|
||||
"this operation requires administrator to perform": "ta operacja wymaga administratora do wykonania"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Serwer LDAP istnieje"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email jest włączone, ale email jest pusty",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon jest włączony, ale numer telefonu jest pusty",
|
||||
"New password cannot contain blank space.": "Nowe hasło nie może zawierać spacji.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "właściciel i nazwa użytkownika nie powinny być puste"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -1,58 +1,60 @@
|
||||
{
|
||||
"account": {
|
||||
"Failed to add user": "Falha ao adicionar usuário",
|
||||
"Get init score failed, error: %w": "Obter pontuação inicial falhou, erro: %w",
|
||||
"Please sign out first": "Por favor, saia da sessão primeiro",
|
||||
"The application does not allow to sign up new account": "O aplicativo não permite a criação de uma nova conta"
|
||||
"Get init score failed, error: %w": "Falha ao obter pontuação inicial, erro: %w",
|
||||
"Please sign out first": "Por favor, saia primeiro",
|
||||
"The application does not allow to sign up new account": "O aplicativo não permite a criação de novas contas"
|
||||
},
|
||||
"auth": {
|
||||
"Challenge method should be S256": "Método de desafio deve ser S256",
|
||||
"Challenge method should be S256": "O método de desafio deve ser S256",
|
||||
"DeviceCode Invalid": "Código de dispositivo inválido",
|
||||
"Failed to create user, user information is invalid: %s": "Falha ao criar usuário, informação do usuário inválida: %s",
|
||||
"Failed to login in: %s": "Falha ao entrar em: %s",
|
||||
"Failed to create user, user information is invalid: %s": "Falha ao criar usuário, as informações são inválidas: %s",
|
||||
"Failed to login in: %s": "Falha ao fazer login em: %s",
|
||||
"Invalid token": "Token inválido",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, mas recebeu: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta via %%s, por favor, use outra forma de se inscrever",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta entre em contato com seu suporte de TI",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, mas recebido: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "A conta do provedor: %s e nome de usuário: %s (%s) não existe e não é permitido criar nova conta via %s, por favor, use outra forma de cadastro",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "A conta do provedor: %s e nome de usuário: %s (%s) não existe e não é permitido criar nova conta, entre em contato com o suporte de TI",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "A conta do provedor: %s e nome de usuário: %s (%s) já está vinculada a outra conta: %s (%s)",
|
||||
"The application: %s does not exist": "O aplicativo: %s não existe",
|
||||
"The login method: login with LDAP is not enabled for the application": "O método de login: login com LDAP não está ativado para a aplicação",
|
||||
"The login method: login with SMS is not enabled for the application": "O método de login: login com SMS não está ativado para a aplicação",
|
||||
"The login method: login with email is not enabled for the application": "O método de login: login com e-mail não está ativado para a aplicação",
|
||||
"The login method: login with face is not enabled for the application": "O método de login: login com reconhecimento facial não está ativado para a aplicação",
|
||||
"The login method: login with password is not enabled for the application": "O método de login: login com senha não está habilitado para o aplicativo",
|
||||
"The application: %s has disabled users to signin": "O aplicativo: %s desativou o login de usuários",
|
||||
"The login method: login with LDAP is not enabled for the application": "O método de login com LDAP não está habilitado para o aplicativo",
|
||||
"The login method: login with SMS is not enabled for the application": "O método de login com SMS não está habilitado para o aplicativo",
|
||||
"The login method: login with email is not enabled for the application": "O método de login com e-mail não está habilitado para o aplicativo",
|
||||
"The login method: login with face is not enabled for the application": "O método de login com reconhecimento facial não está habilitado para o aplicativo",
|
||||
"The login method: login with password is not enabled for the application": "O método de login com senha não está habilitado para o aplicativo",
|
||||
"The organization: %s does not exist": "A organização: %s não existe",
|
||||
"The organization: %s has disabled users to signin": "A organização: %s desativou o login de usuários",
|
||||
"The provider: %s does not exist": "O provedor: %s não existe",
|
||||
"The provider: %s is not enabled for the application": "O provedor: %s não está habilitado para o aplicativo",
|
||||
"Unauthorized operation": "Operação não autorizada",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticação desconhecido (não é senha ou provedor), formulário = %s",
|
||||
"User's tag: %s is not listed in the application's tags": "A tag do usuário: %s não está listada nas tags da aplicação",
|
||||
"User's tag: %s is not listed in the application's tags": "A tag do usuário: %s não está listada nas tags do aplicativo",
|
||||
"UserCode Expired": "Código de usuário expirado",
|
||||
"UserCode Invalid": "Código de usuário inválido",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "usuário pago %s não possui assinatura ativa ou pendente e a aplicação: %s não possui preço padrão",
|
||||
"the application for user %s is not found": "a aplicação para o usuário %s não foi encontrada",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "O usuário pago %s não possui assinatura ativa ou pendente e o aplicativo: %s não possui preço padrão",
|
||||
"the application for user %s is not found": "o aplicativo para o usuário %s não foi encontrado",
|
||||
"the organization: %s is not found": "a organização: %s não foi encontrada"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "O serviço %s e %s não correspondem"
|
||||
},
|
||||
"check": {
|
||||
"%s does not meet the CIDR format requirements: %s": "%s não atende aos requisitos de formato CIDR: %s",
|
||||
"Affiliation cannot be blank": "A filiação não pode estar em branco",
|
||||
"CIDR for IP: %s should not be empty": "CIDR para IP: %s não deve estar vazio",
|
||||
"Default code does not match the code's matching rules": "O código padrão não corresponde às regras de correspondência do código",
|
||||
"%s does not meet the CIDR format requirements: %s": "%s não atende aos requisitos do formato CIDR: %s",
|
||||
"Affiliation cannot be blank": "A afiliação não pode estar em branco",
|
||||
"CIDR for IP: %s should not be empty": "O CIDR para o IP: %s não pode estar vazio",
|
||||
"Default code does not match the code's matching rules": "O código padrão não corresponde às regras de validação do código",
|
||||
"DisplayName cannot be blank": "O nome de exibição não pode estar em branco",
|
||||
"DisplayName is not valid real name": "O nome de exibição não é um nome real válido",
|
||||
"Email already exists": "O e-mail já existe",
|
||||
"Email cannot be empty": "O e-mail não pode estar vazio",
|
||||
"Email is invalid": "O e-mail é inválido",
|
||||
"Email is invalid": "E-mail inválido",
|
||||
"Empty username.": "Nome de usuário vazio.",
|
||||
"Face data does not exist, cannot log in": "Dados faciais não existem, não é possível fazer login",
|
||||
"Face data mismatch": "Incompatibilidade de dados faciais",
|
||||
"Failed to parse client IP: %s": "Falha ao analisar IP do cliente: %s",
|
||||
"Face data mismatch": "Dados faciais não correspondem",
|
||||
"Failed to parse client IP: %s": "Falha ao analisar o IP do cliente: %s",
|
||||
"FirstName cannot be blank": "O primeiro nome não pode estar em branco",
|
||||
"Invitation code cannot be blank": "O código de convite não pode estar em branco",
|
||||
"Invitation code exhausted": "Código de convite esgotado",
|
||||
"Invitation code exhausted": "O código de convite foi esgotado",
|
||||
"Invitation code is invalid": "Código de convite inválido",
|
||||
"Invitation code suspended": "Código de convite suspenso",
|
||||
"LDAP user name or password incorrect": "Nome de usuário ou senha LDAP incorretos",
|
||||
@@ -62,7 +64,7 @@
|
||||
"Password cannot be empty": "A senha não pode estar vazia",
|
||||
"Phone already exists": "O telefone já existe",
|
||||
"Phone cannot be empty": "O telefone não pode estar vazio",
|
||||
"Phone number is invalid": "O número de telefone é inválido",
|
||||
"Phone number is invalid": "Número de telefone inválido",
|
||||
"Please register using the email corresponding to the invitation code": "Por favor, registre-se usando o e-mail correspondente ao código de convite",
|
||||
"Please register using the phone corresponding to the invitation code": "Por favor, registre-se usando o telefone correspondente ao código de convite",
|
||||
"Please register using the username corresponding to the invitation code": "Por favor, registre-se usando o nome de usuário correspondente ao código de convite",
|
||||
@@ -71,66 +73,69 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "O usuário está proibido de entrar, entre em contato com o administrador",
|
||||
"The user: %s doesn't exist in LDAP server": "O usuário: %s não existe no servidor LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "O nome de usuário pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "O valor \\\"%s\\\" para o campo de conta \\\"%s\\\" não corresponde à expressão regular do item de conta",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "O valor \\\"%s\\\" para o campo de registro \\\"%s\\\" não corresponde à expressão regular do item de registro da aplicação \\\"%s\\\"",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "O valor \\\"%s\\\" para o campo de conta \\\"%s\\\" não corresponde à expressão regular definida",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "O valor \\\"%s\\\" para o campo de registro \\\"%s\\\" não corresponde à expressão regular definida na aplicação \\\"%s\\\"",
|
||||
"Username already exists": "O nome de usuário já existe",
|
||||
"Username cannot be an email address": "O nome de usuário não pode ser um endereço de e-mail",
|
||||
"Username cannot contain white spaces": "O nome de usuário não pode conter espaços em branco",
|
||||
"Username cannot start with a digit": "O nome de usuário não pode começar com um dígito",
|
||||
"Username is too long (maximum is 255 characters).": "Nome de usuário é muito longo (máximo é 255 caracteres).",
|
||||
"Username must have at least 2 characters": "Nome de usuário deve ter pelo menos 2 caracteres",
|
||||
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "O nome de usuário suporta formato de e-mail. Além disso, o nome de usuário pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado. Preste atenção também ao formato de e-mail.",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Você digitou a senha ou o código incorretos muitas vezes, aguarde %d minutos e tente novamente",
|
||||
"Your IP address: %s has been banned according to the configuration of: ": "Seu endereço IP: %s foi banido de acordo com a configuração de: ",
|
||||
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Sua senha expirou. Por favor, redefina sua senha clicando em \\\"Esqueci a senha\\\"",
|
||||
"Username cannot start with a digit": "O nome de usuário não pode começar com um número",
|
||||
"Username is too long (maximum is 255 characters).": "O nome de usuário é muito longo (máximo de 255 caracteres).",
|
||||
"Username must have at least 2 characters": "O nome de usuário deve ter pelo menos 2 caracteres",
|
||||
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "O nome de usuário suporta o formato de e-mail. Além disso, pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado. Também preste atenção ao formato do e-mail.",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Você digitou a senha ou o código incorretos muitas vezes. Aguarde %d minutos e tente novamente",
|
||||
"Your IP address: %s has been banned according to the configuration of: ": "Seu endereço IP: %s foi bloqueado de acordo com a configuração de: ",
|
||||
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Sua senha expirou. Por favor, redefina-a clicando em \\\"Esqueci a senha\\\"",
|
||||
"Your region is not allow to signup by phone": "Sua região não permite cadastro por telefone",
|
||||
"password or code is incorrect": "senha ou código incorreto",
|
||||
"password or code is incorrect, you have %s remaining chances": "senha ou código está incorreto, você tem %s chances restantes",
|
||||
"unsupported password type: %s": "tipo de senha não suportado: %s"
|
||||
"password or code is incorrect": "Senha ou código incorreto",
|
||||
"password or code is incorrect, you have %s remaining chances": "Senha ou código incorreto, você tem %s tentativas restantes",
|
||||
"unsupported password type: %s": "Tipo de senha não suportado: %s"
|
||||
},
|
||||
"enforcer": {
|
||||
"the adapter: %s is not found": "o adaptador: %s não foi encontrado"
|
||||
"the adapter: %s is not found": "O adaptador: %s não foi encontrado"
|
||||
},
|
||||
"general": {
|
||||
"Failed to import groups": "Falha ao importar grupos",
|
||||
"Failed to import users": "Falha ao importar usuários",
|
||||
"Missing parameter": "Parâmetro faltante",
|
||||
"Only admin user can specify user": "Apenas usuário administrador pode especificar usuário",
|
||||
"Please login first": "Faça login primeiro",
|
||||
"The organization: %s should have one application at least": "A organização: %s deve ter pelo menos uma aplicação",
|
||||
"Missing parameter": "Parâmetro ausente",
|
||||
"Only admin user can specify user": "Apenas um administrador pode especificar um usuário",
|
||||
"Please login first": "Por favor, faça login primeiro",
|
||||
"The organization: %s should have one application at least": "A organização: %s deve ter pelo menos um aplicativo",
|
||||
"The user: %s doesn't exist": "O usuário: %s não existe",
|
||||
"Wrong userId": "ID de usuário incorreto",
|
||||
"don't support captchaProvider: ": "não suporta captchaProvider: ",
|
||||
"don't support captchaProvider: ": "captchaProvider não suportado: ",
|
||||
"this operation is not allowed in demo mode": "esta operação não é permitida no modo de demonstração",
|
||||
"this operation requires administrator to perform": "esta operação requer um administrador para executar"
|
||||
"this operation requires administrator to perform": "esta operação requer privilégios de administrador"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "O convite %s não existe"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Servidor LDAP existe"
|
||||
"Ldap server exist": "O servidor LDAP existe"
|
||||
},
|
||||
"link": {
|
||||
"Please link first": "Vincule primeiro",
|
||||
"This application has no providers": "Este aplicativo não tem provedores",
|
||||
"This application has no providers of type": "Este aplicativo não tem provedores do tipo",
|
||||
"Please link first": "Por favor, vincule primeiro",
|
||||
"This application has no providers": "Este aplicativo não possui provedores",
|
||||
"This application has no providers of type": "Este aplicativo não possui provedores do tipo especificado",
|
||||
"This provider can't be unlinked": "Este provedor não pode ser desvinculado",
|
||||
"You are not the global admin, you can't unlink other users": "Você não é o administrador global, não pode desvincular outros usuários",
|
||||
"You can't unlink yourself, you are not a member of any application": "Você não pode se desvincular, não é membro de nenhum aplicativo"
|
||||
"You can't unlink yourself, you are not a member of any application": "Você não pode se desvincular, pois não é membro de nenhum aplicativo"
|
||||
},
|
||||
"organization": {
|
||||
"Only admin can modify the %s.": "Apenas o administrador pode modificar o %s.",
|
||||
"The %s is immutable.": "O %s é imutável.",
|
||||
"Unknown modify rule %s.": "Regra de modificação %s desconhecida.",
|
||||
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "nte desativada. Observe que todos os usuários na organização 'built-in' são administradores globais no Casdoor. Consulte a documentação: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Se ainda desejar criar um usuário para a organização 'built-in', acesse a página de configurações da organização e habilite a opção 'Possui consentimento de privilégios'."
|
||||
"Unknown modify rule %s.": "Regra de modificação desconhecida: %s.",
|
||||
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "A adição de novos usuários à organização 'built-in' está desativada. Observe que todos os usuários nessa organização são administradores globais no Casdoor. Consulte a documentação: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Se ainda desejar criar um usuário, vá até a página de configurações da organização e habilite a opção 'Possui consentimento de privilégios'."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "A permissão: \\\"%s\\\" não existe"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Id do aplicativo inválido",
|
||||
"the provider: %s does not exist": "o provedor: %s não existe"
|
||||
"Invalid application id": "ID de aplicativo inválido",
|
||||
"the provider: %s does not exist": "O provedor: %s não existe"
|
||||
},
|
||||
"resource": {
|
||||
"User is nil for tag: avatar": "Usuário é nulo para tag: avatar",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nome de usuário ou fullFilePath está vazio: username = %s, fullFilePath = %s"
|
||||
"User is nil for tag: avatar": "Usuário nulo para a tag: avatar",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nome de usuário ou fullFilePath vazio: username = %s, fullFilePath = %s"
|
||||
},
|
||||
"saml": {
|
||||
"Application %s not found": "Aplicativo %s não encontrado"
|
||||
@@ -144,7 +149,7 @@
|
||||
"Invalid phone receivers: %s": "Destinatários de telefone inválidos: %s"
|
||||
},
|
||||
"storage": {
|
||||
"The objectKey: %s is not allowed": "O objectKey: %s não é permitido",
|
||||
"The objectKey: %s is not allowed": "A chave de objeto: %s não é permitida",
|
||||
"The provider type: %s is not supported": "O tipo de provedor: %s não é suportado"
|
||||
},
|
||||
"subscription": {
|
||||
@@ -152,40 +157,41 @@
|
||||
},
|
||||
"token": {
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s não é suportado neste aplicativo",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret errado",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret incorreto",
|
||||
"Invalid client_id": "client_id inválido",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI de redirecionamento: %s não existe na lista de URI de redirecionamento permitida",
|
||||
"Token not found, invalid accessToken": "Token não encontrado, token de acesso inválido"
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "O URI de redirecionamento: %s não existe na lista de URIs permitidos",
|
||||
"Token not found, invalid accessToken": "Token não encontrado, accessToken inválido"
|
||||
},
|
||||
"user": {
|
||||
"Display name cannot be empty": "Nome de exibição não pode ser vazio",
|
||||
"MFA email is enabled but email is empty": "MFA por e-mail está ativado, mas o e-mail está vazio",
|
||||
"MFA phone is enabled but phone number is empty": "MFA por telefone está ativado, mas o número de telefone está vazio",
|
||||
"New password cannot contain blank space.": "A nova senha não pode conter espaço em branco.",
|
||||
"the user's owner and name should not be empty": "o proprietário e o nome do usuário não devem estar vazios"
|
||||
"Display name cannot be empty": "O nome de exibição não pode estar vazio",
|
||||
"MFA email is enabled but email is empty": "MFA por e-mail está habilitado, mas o e-mail está vazio",
|
||||
"MFA phone is enabled but phone number is empty": "MFA por telefone está habilitado, mas o número de telefone está vazio",
|
||||
"New password cannot contain blank space.": "A nova senha não pode conter espaços em branco.",
|
||||
"The new password must be different from your current password": "A nova senha deve ser diferente da senha atual",
|
||||
"the user's owner and name should not be empty": "O proprietário e o nome do usuário não devem estar vazios"
|
||||
},
|
||||
"util": {
|
||||
"No application is found for userId: %s": "Nenhum aplicativo encontrado para userId: %s",
|
||||
"No provider for category: %s is found for application: %s": "Nenhum provedor para categoria: %s encontrado para aplicativo: %s",
|
||||
"No application is found for userId: %s": "Nenhum aplicativo encontrado para o userId: %s",
|
||||
"No provider for category: %s is found for application: %s": "Nenhum provedor da categoria: %s encontrado para o aplicativo: %s",
|
||||
"The provider: %s is not found": "O provedor: %s não foi encontrado"
|
||||
},
|
||||
"verification": {
|
||||
"Invalid captcha provider.": "Provedor de captcha inválido.",
|
||||
"Phone number is invalid in your region %s": "Número de telefone é inválido em sua região %s",
|
||||
"Phone number is invalid in your region %s": "Número de telefone inválido na sua região %s",
|
||||
"The verification code has already been used!": "O código de verificação já foi utilizado!",
|
||||
"The verification code has not been sent yet!": "O código de verificação ainda não foi enviado!",
|
||||
"Turing test failed.": "Teste de Turing falhou.",
|
||||
"Turing test failed.": "O teste de Turing falhou.",
|
||||
"Unable to get the email modify rule.": "Não foi possível obter a regra de modificação de e-mail.",
|
||||
"Unable to get the phone modify rule.": "Não foi possível obter a regra de modificação de telefone.",
|
||||
"Unknown type": "Tipo desconhecido",
|
||||
"Wrong verification code!": "Código de verificação incorreto!",
|
||||
"You should verify your code in %d min!": "Você deve verificar seu código em %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "por favor, adicione um provedor de SMS à lista \\\"Providers\\\" da aplicação: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "por favor, adicione um provedor de e-mail à lista \\\"Providers\\\" da aplicação: %s",
|
||||
"the user does not exist, please sign up first": "o usuário não existe, cadastre-se primeiro"
|
||||
"You should verify your code in %d min!": "Você deve verificar seu código em %d minuto(s)!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "Adicione um provedor de SMS à lista \\\"Providers\\\" do aplicativo: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "Adicione um provedor de e-mail à lista \\\"Providers\\\" do aplicativo: %s",
|
||||
"the user does not exist, please sign up first": "O usuário não existe, cadastre-se primeiro"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, chame WebAuthnSigninBegin primeiro"
|
||||
"Found no credentials for this user": "Nenhuma credencial encontrada para este usuário",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, inicie com WebAuthnSigninBegin primeiro"
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Не удалось войти в систему: %s",
|
||||
"Invalid token": "Недействительный токен",
|
||||
"State expected: %s, but got: %s": "Ожидался статус: %s, но получен: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Аккаунт провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован через %%s, пожалуйста, используйте другой способ регистрации",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Аккаунт провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован через %s, пожалуйста, используйте другой способ регистрации",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Аккаунт для провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован как новый аккаунт. Пожалуйста, обратитесь в службу поддержки IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Аккаунт поставщика: %s и имя пользователя: %s (%s) уже связаны с другим аккаунтом: %s (%s)",
|
||||
"The application: %s does not exist": "Приложение: %s не существует",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Метод входа через LDAP отключен для этого приложения",
|
||||
"The login method: login with SMS is not enabled for the application": "Метод входа через SMS отключен для этого приложения",
|
||||
"The login method: login with email is not enabled for the application": "Метод входа через электронную почту отключен для этого приложения",
|
||||
"The login method: login with face is not enabled for the application": "Метод входа через распознавание лица отключен для этого приложения",
|
||||
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
||||
"The organization: %s does not exist": "Организация: %s не существует",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Провайдер: %s не существует",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
||||
"Unauthorized operation": "Несанкционированная операция",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "эта операция недоступна в демонстрационном режиме",
|
||||
"this operation requires administrator to perform": "эта операция требует прав администратора"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-сервер существует"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA по электронной почте включен, но электронная почта не указана",
|
||||
"MFA phone is enabled but phone number is empty": "MFA по телефону включен, но номер телефона не указан",
|
||||
"New password cannot contain blank space.": "Новый пароль не может содержать пробелы.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "владелец и имя пользователя не должны быть пустыми"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Prihlásenie zlyhalo: %s",
|
||||
"Invalid token": "Neplatný token",
|
||||
"State expected: %s, but got: %s": "Očakávaný stav: %s, ale dostali sme: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet cez %%s, prosím použite iný spôsob registrácie",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet cez %s, prosím použite iný spôsob registrácie",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet, prosím kontaktujte vašu IT podporu",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) je už prepojený s iným účtom: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikácia: %s neexistuje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou LDAP nie je pre aplikáciu povolená",
|
||||
"The login method: login with SMS is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou SMS nie je pre aplikáciu povolená",
|
||||
"The login method: login with email is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou e-mailu nie je pre aplikáciu povolená",
|
||||
"The login method: login with face is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou tváre nie je pre aplikáciu povolená",
|
||||
"The login method: login with password is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou hesla nie je pre aplikáciu povolená",
|
||||
"The organization: %s does not exist": "Organizácia: %s neexistuje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Poskytovatel: %s neexistuje",
|
||||
"The provider: %s is not enabled for the application": "Poskytovateľ: %s nie je pre aplikáciu povolený",
|
||||
"Unauthorized operation": "Neautorizovaná operácia",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "táto operácia nie je povolená v demo režime",
|
||||
"this operation requires administrator to perform": "táto operácia vyžaduje vykonanie administrátorom"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP server existuje"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-mail je zapnutý, ale e-mail je prázdny",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefón je zapnutý, ale telefónne číslo je prázdne",
|
||||
"New password cannot contain blank space.": "Nové heslo nemôže obsahovať medzery.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "vlastník a meno používateľa nesmú byť prázdne"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Misslyckades logga in: %s",
|
||||
"Invalid token": "Ogiltig token",
|
||||
"State expected: %s, but got: %s": "Förväntat tillstånd: %s, men fick: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto via %%s, använd ett annat sätt att registrera dig",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto via %s, använd ett annat sätt att registrera dig",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto, kontakta din IT-support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Kontot för leverantör: %s och användarnamn: %s (%s) är redan länkat till ett annat konto: %s (%s)",
|
||||
"The application: %s does not exist": "Applikationen: %s finns inte",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Inloggningsmetoden: inloggning med LDAP är inte aktiverad för applikationen",
|
||||
"The login method: login with SMS is not enabled for the application": "Inloggningsmetoden: inloggning med SMS är inte aktiverad för applikationen",
|
||||
"The login method: login with email is not enabled for the application": "Inloggningsmetoden: inloggning med e-post är inte aktiverad för applikationen",
|
||||
"The login method: login with face is not enabled for the application": "Inloggningsmetoden: inloggning med ansikte är inte aktiverad för applikationen",
|
||||
"The login method: login with password is not enabled for the application": "Inloggningsmetoden: inloggning med lösenord är inte aktiverad för applikationen",
|
||||
"The organization: %s does not exist": "Organisationen: %s finns inte",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Leverantören: %s finns inte",
|
||||
"The provider: %s is not enabled for the application": "Leverantören: %s är inte aktiverad för applikationen",
|
||||
"Unauthorized operation": "Obehörig åtgärd",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "denna åtgärd är inte tillåten i demoläge",
|
||||
"this operation requires administrator to perform": "denna åtgärd kräver administratör för att genomföras"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-servern finns redan"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-post är aktiverat men e-post är tom",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefon är aktiverat men telefonnummer är tomt",
|
||||
"New password cannot contain blank space.": "Nytt lösenord får inte innehålla mellanslag.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "användarens ägare och namn får inte vara tomma"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Giriş yapılamadı: %s",
|
||||
"Invalid token": "Geçersiz token",
|
||||
"State expected: %s, but got: %s": "Beklenen durum: %s, fakat alınan: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve %%s ile yeni hesap açılmasına izin verilmiyor, lütfen başka yöntemle kaydolun",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve %s ile yeni hesap açılmasına izin verilmiyor, lütfen başka yöntemle kaydolun",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve yeni hesap açılmasına izin verilmiyor, lütfen BT destek ile iletişime geçin",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Provider: %s ve kullanıcı adı: %s (%s) zaten başka bir hesaba bağlı: %s (%s)",
|
||||
"The application: %s does not exist": "Uygulama: %s bulunamadı",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Uygulama için LDAP ile giriş yöntemi etkin değil",
|
||||
"The login method: login with SMS is not enabled for the application": "Uygulama için SMS ile giriş yöntemi etkin değil",
|
||||
"The login method: login with email is not enabled for the application": "Uygulama için e-posta ile giriş yöntemi etkin değil",
|
||||
"The login method: login with face is not enabled for the application": "Uygulama için yüz ile giriş yöntemi etkin değil",
|
||||
"The login method: login with password is not enabled for the application": "Şifre ile giriş yöntemi bu uygulama için etkin değil",
|
||||
"The organization: %s does not exist": "Organizasyon: %s mevcut değil",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Sağlayıcı: %s mevcut değil",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s bu uygulama için etkin değil",
|
||||
"Unauthorized operation": "Yetkisiz işlem",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "bu işlem demo modunda izin verilmiyor",
|
||||
"this operation requires administrator to perform": "bu işlem yönetici tarafından gerçekleştirilmelidir"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP sunucusu zaten var"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-postası etkin ancak e-posta boş",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefonu etkin ancak telefon numarası boş",
|
||||
"New password cannot contain blank space.": "Yeni şifre boşluk içeremez.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "kullanıcının sahibi ve adı boş olmamalıdır"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Не вдалося увійти: %s",
|
||||
"Invalid token": "Недійсний токен",
|
||||
"State expected: %s, but got: %s": "Очікувалося стан: %s, але отримано: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий через %%s, використайте інший спосіб",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий через %s, використайте інший спосіб",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий, зверніться до IT-підтримки",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) уже пов’язаний з іншим обліковим записом: %s (%s)",
|
||||
"The application: %s does not exist": "Додаток: %s не існує",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Метод входу через LDAP не увімкнено для цього додатка",
|
||||
"The login method: login with SMS is not enabled for the application": "Метод входу через SMS не увімкнено для цього додатка",
|
||||
"The login method: login with email is not enabled for the application": "Метод входу через email не увімкнено для цього додатка",
|
||||
"The login method: login with face is not enabled for the application": "Метод входу через обличчя не увімкнено для цього додатка",
|
||||
"The login method: login with password is not enabled for the application": "Метод входу через пароль не увімкнено для цього додатка",
|
||||
"The organization: %s does not exist": "Організація: %s не існує",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Провайдер: %s не існує",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не увімкнено для цього додатка",
|
||||
"Unauthorized operation": "Неавторизована операція",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "ця операція недоступна в демо-режимі",
|
||||
"this operation requires administrator to perform": "ця операція потребує прав адміністратора"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Сервер LDAP існує"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email увімкнено, але email порожній",
|
||||
"MFA phone is enabled but phone number is empty": "MFA телефон увімкнено, але номер телефону порожній",
|
||||
"New password cannot contain blank space.": "Новий пароль не може містити пробіли.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "власник ім’я користувача не повинні бути порожніми"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "Đăng nhập không thành công: %s",
|
||||
"Invalid token": "Mã thông báo không hợp lệ",
|
||||
"State expected: %s, but got: %s": "Trạng thái dự kiến: %s, nhưng nhận được: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký làm tài khoản mới qua %%s, vui lòng sử dụng cách khác để đăng ký",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký làm tài khoản mới qua %s, vui lòng sử dụng cách khác để đăng ký",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký như một tài khoản mới, vui lòng liên hệ với bộ phận hỗ trợ công nghệ thông tin của bạn",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) đã được liên kết với tài khoản khác: %s (%s)",
|
||||
"The application: %s does not exist": "Ứng dụng: %s không tồn tại",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "Phương thức đăng nhập bằng LDAP chưa được bật cho ứng dụng",
|
||||
"The login method: login with SMS is not enabled for the application": "Phương thức đăng nhập bằng SMS chưa được bật cho ứng dụng",
|
||||
"The login method: login with email is not enabled for the application": "Phương thức đăng nhập bằng email chưa được bật cho ứng dụng",
|
||||
"The login method: login with face is not enabled for the application": "Phương thức đăng nhập bằng khuôn mặt chưa được bật cho ứng dụng",
|
||||
"The login method: login with password is not enabled for the application": "Phương thức đăng nhập: đăng nhập bằng mật khẩu không được kích hoạt cho ứng dụng",
|
||||
"The organization: %s does not exist": "Tổ chức: %s không tồn tại",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The provider: %s does not exist": "Nhà cung cấp: %s không tồn tại",
|
||||
"The provider: %s is not enabled for the application": "Nhà cung cấp: %s không được kích hoạt cho ứng dụng",
|
||||
"Unauthorized operation": "Hoạt động không được ủy quyền",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "thao tác này không được phép trong chế độ demo",
|
||||
"this operation requires administrator to perform": "thao tác này yêu cầu quản trị viên thực hiện"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Máy chủ LDAP tồn tại"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email đã bật nhưng email trống",
|
||||
"MFA phone is enabled but phone number is empty": "MFA điện thoại đã bật nhưng số điện thoại trống",
|
||||
"New password cannot contain blank space.": "Mật khẩu mới không thể chứa dấu trắng.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "chủ sở hữu và tên người dùng không được để trống"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -12,16 +12,18 @@
|
||||
"Failed to login in: %s": "登录失败: %s",
|
||||
"Invalid token": "无效token",
|
||||
"State expected: %s, but got: %s": "期望状态为: %s, 实际状态为: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s与用户名: %s (%s)已经与其他账户绑定: %s (%s)",
|
||||
"The application: %s does not exist": "应用%s不存在",
|
||||
"The application: %s has disabled users to signin": "应用: %s 禁止用户登录",
|
||||
"The login method: login with LDAP is not enabled for the application": "该应用禁止采用LDAP登录方式",
|
||||
"The login method: login with SMS is not enabled for the application": "该应用禁止采用短信登录方式",
|
||||
"The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式",
|
||||
"The login method: login with face is not enabled for the application": "该应用禁止采用人脸登录",
|
||||
"The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
|
||||
"The organization: %s does not exist": "组织: %s 不存在",
|
||||
"The organization: %s has disabled users to signin": "组织: %s 禁止用户登录",
|
||||
"The provider: %s does not exist": "提供商: %s 不存在",
|
||||
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
|
||||
"Unauthorized operation": "未授权的操作",
|
||||
@@ -104,6 +106,9 @@
|
||||
"this operation is not allowed in demo mode": "demo模式下不允许该操作",
|
||||
"this operation requires administrator to perform": "只有管理员才能进行此操作"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "邀请%s不存在"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP服务器已存在"
|
||||
},
|
||||
@@ -162,6 +167,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA 电子邮件已启用,但电子邮件为空",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 电话已启用,但电话号码为空",
|
||||
"New password cannot contain blank space.": "新密码不可以包含空格",
|
||||
"The new password must be different from your current password": "新密码必须与您当前的密码不同",
|
||||
"the user's owner and name should not be empty": "用户的组织和名称不能为空"
|
||||
},
|
||||
"util": {
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@@ -64,6 +65,25 @@ func (idp *CustomIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
return idp.Config.Exchange(ctx, code)
|
||||
}
|
||||
|
||||
func getNestedValue(data map[string]interface{}, path string) (interface{}, error) {
|
||||
keys := strings.Split(path, ".")
|
||||
var val interface{} = data
|
||||
|
||||
for _, key := range keys {
|
||||
m, ok := val.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("path '%s' is not valid: %s is not a map", path, key)
|
||||
}
|
||||
|
||||
val, ok = m[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key '%s' not found in path '%s'", key, path)
|
||||
}
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type CustomUserInfo struct {
|
||||
Id string `mapstructure:"id"`
|
||||
Username string `mapstructure:"username"`
|
||||
@@ -108,11 +128,11 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
|
||||
// map user info
|
||||
for k, v := range idp.UserMapping {
|
||||
_, ok := dataMap[v]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot find %s in user from custom provider", v)
|
||||
val, err := getNestedValue(dataMap, v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot find %s in user from custom provider: %v", v, err)
|
||||
}
|
||||
dataMap[k] = dataMap[v]
|
||||
dataMap[k] = val
|
||||
}
|
||||
|
||||
// try to parse id to string
|
||||
|
11
idp/lark.go
11
idp/lark.go
@@ -135,6 +135,7 @@ func (idp *LarkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
"open_id": "ou-caecc734c2e3328a62489fe0648c4b98779515d3",
|
||||
"union_id": "on-d89jhsdhjsajkda7828enjdj328ydhhw3u43yjhdj",
|
||||
"email": "zhangsan@feishu.cn",
|
||||
"enterprise_email": "zhangsan@company.com",
|
||||
"user_id": "5d9bdxxx",
|
||||
"mobile": "+86130002883xx",
|
||||
"tenant_key": "736588c92lxf175d",
|
||||
@@ -160,6 +161,7 @@ type LarkUserInfo struct {
|
||||
OpenId string `json:"open_id"`
|
||||
UnionId string `json:"union_id"`
|
||||
Email string `json:"email"`
|
||||
EnterpriseEmail string `json:"enterprise_email"`
|
||||
UserId string `json:"user_id"`
|
||||
Mobile string `json:"mobile"`
|
||||
TenantKey string `json:"tenant_key"`
|
||||
@@ -168,7 +170,6 @@ type LarkUserInfo struct {
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// GetUserInfo use LarkAccessToken gotten before return LinkedInUserInf
|
||||
// GetUserInfo use LarkAccessToken gotten before return LinkedInUserInfo
|
||||
// get more detail via: https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin?context=linkedin/consumer/context
|
||||
func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
@@ -207,6 +208,12 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use enterprise_email as fallback when email is empty
|
||||
email := larkUserInfo.Data.Email
|
||||
if email == "" {
|
||||
email = larkUserInfo.Data.EnterpriseEmail
|
||||
}
|
||||
|
||||
var phoneNumber string
|
||||
var countryCode string
|
||||
if len(larkUserInfo.Data.Mobile) != 0 {
|
||||
@@ -222,7 +229,7 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
Id: larkUserInfo.Data.OpenId,
|
||||
DisplayName: larkUserInfo.Data.Name,
|
||||
Username: larkUserInfo.Data.UserId,
|
||||
Email: larkUserInfo.Data.Email,
|
||||
Email: email,
|
||||
AvatarUrl: larkUserInfo.Data.AvatarUrl,
|
||||
Phone: phoneNumber,
|
||||
CountryCode: countryCode,
|
||||
|
@@ -17,7 +17,6 @@ package idp
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -29,7 +28,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/skip2/go-qrcode"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@@ -324,10 +322,7 @@ func GetWechatOfficialAccountQRCode(clientId string, clientSecret string, provid
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var png []byte
|
||||
png, err = qrcode.Encode(data.URL, qrcode.Medium, 256)
|
||||
base64Image := base64.StdEncoding.EncodeToString(png)
|
||||
return base64Image, data.Ticket, nil
|
||||
return data.URL, data.Ticket, nil
|
||||
}
|
||||
|
||||
func VerifyWechatSignature(token string, nonce string, timestamp string, signature string) bool {
|
||||
|
@@ -37,7 +37,8 @@
|
||||
"UA",
|
||||
"KZ",
|
||||
"CZ",
|
||||
"SK"
|
||||
"SK",
|
||||
"AZ"
|
||||
],
|
||||
"defaultAvatar": "",
|
||||
"defaultApplication": "",
|
||||
@@ -66,13 +67,15 @@
|
||||
"kk",
|
||||
"fa",
|
||||
"cs",
|
||||
"sk"
|
||||
"sk",
|
||||
"az"
|
||||
],
|
||||
"masterPassword": "",
|
||||
"defaultPassword": "",
|
||||
"initScore": 2000,
|
||||
"enableSoftDeletion": false,
|
||||
"isProfilePublic": true,
|
||||
"disableSignin": false,
|
||||
"accountItems": []
|
||||
}
|
||||
],
|
||||
@@ -87,6 +90,7 @@
|
||||
"cert": "",
|
||||
"enablePassword": true,
|
||||
"enableSignUp": true,
|
||||
"disableSignin": false,
|
||||
"clientId": "",
|
||||
"clientSecret": "",
|
||||
"providers": [
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@@ -149,10 +150,6 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
}
|
||||
|
||||
r := m.GetSearchRequest()
|
||||
if r.FilterString() == "(objectClass=*)" {
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
|
||||
select {
|
||||
@@ -162,6 +159,43 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
default:
|
||||
}
|
||||
|
||||
if strings.EqualFold(r.FilterString(), "(objectClass=*)") && (string(r.BaseObject()) == "" || strings.EqualFold(string(r.BaseObject()), "cn=Subschema")) {
|
||||
handleRootSearch(w, &r, &res, m)
|
||||
return
|
||||
}
|
||||
|
||||
var isGroupSearch bool = false
|
||||
filter := r.Filter()
|
||||
if eq, ok := filter.(message.FilterEqualityMatch); ok && strings.EqualFold(string(eq.AttributeDesc()), "objectClass") && strings.EqualFold(string(eq.AssertionValue()), "posixGroup") {
|
||||
isGroupSearch = true
|
||||
}
|
||||
|
||||
if isGroupSearch {
|
||||
groups, code := GetFilteredGroups(m, string(r.BaseObject()), r.FilterString())
|
||||
if code != ldap.LDAPResultSuccess {
|
||||
res.SetResultCode(code)
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
dn := fmt.Sprintf("cn=%s,%s", group.Name, string(r.BaseObject()))
|
||||
e := ldap.NewSearchResultEntry(dn)
|
||||
e.AddAttribute("cn", message.AttributeValue(group.Name))
|
||||
gidNumberStr := fmt.Sprintf("%v", hash(group.Name))
|
||||
e.AddAttribute("gidNumber", message.AttributeValue(gidNumberStr))
|
||||
users := object.GetGroupUsersWithoutError(group.GetId())
|
||||
for _, user := range users {
|
||||
e.AddAttribute("memberUid", message.AttributeValue(user.Name))
|
||||
}
|
||||
e.AddAttribute("objectClass", "posixGroup")
|
||||
w.Write(e)
|
||||
}
|
||||
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
|
||||
users, code := GetFilteredUsers(m)
|
||||
if code != ldap.LDAPResultSuccess {
|
||||
res.SetResultCode(code)
|
||||
@@ -200,6 +234,46 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
w.Write(res)
|
||||
}
|
||||
|
||||
func handleRootSearch(w ldap.ResponseWriter, r *message.SearchRequest, res *message.SearchResultDone, m *ldap.Message) {
|
||||
if len(r.Attributes()) == 0 {
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
firstAttr := string(r.Attributes()[0])
|
||||
|
||||
if string(r.BaseObject()) == "" {
|
||||
// Handle special root DSE requests
|
||||
if strings.EqualFold(firstAttr, "namingContexts") {
|
||||
orgs, code := GetFilteredOrganizations(m)
|
||||
if code != ldap.LDAPResultSuccess {
|
||||
res.SetResultCode(code)
|
||||
w.Write(res)
|
||||
return
|
||||
}
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
dnlist := make([]message.AttributeValue, len(orgs))
|
||||
for i, org := range orgs {
|
||||
dnlist[i] = message.AttributeValue(fmt.Sprintf("ou=%s", org.Name))
|
||||
}
|
||||
e.AddAttribute("namingContexts", dnlist...)
|
||||
w.Write(e)
|
||||
} else if strings.EqualFold(firstAttr, "subschemaSubentry") {
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
e.AddAttribute("subschemaSubentry", message.AttributeValue("cn=Subschema"))
|
||||
w.Write(e)
|
||||
}
|
||||
} else if strings.EqualFold(firstAttr, "objectclasses") && strings.EqualFold(string(r.BaseObject()), "cn=Subschema") {
|
||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
||||
e.AddAttribute("objectClasses", []message.AttributeValue{
|
||||
"( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )",
|
||||
"( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) )",
|
||||
}...)
|
||||
w.Write(e)
|
||||
}
|
||||
|
||||
w.Write(res)
|
||||
}
|
||||
|
||||
func hash(s string) uint32 {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(s))
|
||||
|
60
ldap/util.go
60
ldap/util.go
@@ -184,6 +184,10 @@ func buildUserFilterCondition(filter interface{}) (builder.Cond, error) {
|
||||
case message.FilterEqualityMatch:
|
||||
attr := string(f.AttributeDesc())
|
||||
|
||||
if strings.EqualFold(attr, "objectclass") && strings.EqualFold(string(f.AssertionValue()), "posixAccount") {
|
||||
return builder.Expr("1 = 1"), nil
|
||||
}
|
||||
|
||||
if attr == ldapMemberOfAttr {
|
||||
var names []string
|
||||
groupId := string(f.AssertionValue())
|
||||
@@ -200,6 +204,9 @@ func buildUserFilterCondition(filter interface{}) (builder.Cond, error) {
|
||||
}
|
||||
return builder.Eq{field: string(f.AssertionValue())}, nil
|
||||
case message.FilterPresent:
|
||||
if strings.EqualFold(string(f), "objectclass") {
|
||||
return builder.Expr("1 = 1"), nil
|
||||
}
|
||||
field, err := getUserFieldFromAttribute(string(f))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -321,6 +328,59 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFilteredGroups(m *ldap.Message, baseDN string, filterStr string) ([]*object.Group, int) {
|
||||
name, org, code := getNameAndOrgFromFilter(baseDN, filterStr)
|
||||
if code != ldap.LDAPResultSuccess {
|
||||
return nil, code
|
||||
}
|
||||
|
||||
var groups []*object.Group
|
||||
var err error
|
||||
|
||||
if name == "*" {
|
||||
if m.Client.IsGlobalAdmin && org == "*" {
|
||||
groups, err = object.GetGlobalGroups()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
|
||||
groups, err = object.GetGroups(org)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||
}
|
||||
} else {
|
||||
return nil, ldap.LDAPResultNoSuchObject
|
||||
}
|
||||
|
||||
return groups, ldap.LDAPResultSuccess
|
||||
}
|
||||
|
||||
func GetFilteredOrganizations(m *ldap.Message) ([]*object.Organization, int) {
|
||||
if m.Client.IsGlobalAdmin {
|
||||
organizations, err := object.GetOrganizations("")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return organizations, ldap.LDAPResultSuccess
|
||||
} else if m.Client.IsOrgAdmin {
|
||||
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
|
||||
user, err := object.GetUser(requestUserId)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
organization, err := object.GetOrganizationByUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return []*object.Organization{organization}, ldap.LDAPResultSuccess
|
||||
} else {
|
||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||
}
|
||||
}
|
||||
|
||||
// get user password with hash type prefix
|
||||
// TODO not handle salt yet
|
||||
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
||||
|
@@ -67,6 +67,7 @@ type Application struct {
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||
Order int `json:"order"`
|
||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
@@ -75,6 +76,7 @@ type Application struct {
|
||||
HeaderHtml string `xorm:"mediumtext" json:"headerHtml"`
|
||||
EnablePassword bool `json:"enablePassword"`
|
||||
EnableSignUp bool `json:"enableSignUp"`
|
||||
DisableSignin bool `json:"disableSignin"`
|
||||
EnableSigninSession bool `json:"enableSigninSession"`
|
||||
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
|
@@ -16,6 +16,8 @@ package object
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/casdoor/casdoor/cred"
|
||||
)
|
||||
|
||||
type ValidatorFunc func(password string) string
|
||||
@@ -96,3 +98,26 @@ func checkPasswordComplexity(password string, options []string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CheckPasswordNotSameAsCurrent checks if the new password is different from the current password
|
||||
func CheckPasswordNotSameAsCurrent(user *User, newPassword string, organization *Organization) bool {
|
||||
if user.Password == "" {
|
||||
// User doesn't have a password set (e.g., OAuth-only users), allow any password
|
||||
return true
|
||||
}
|
||||
|
||||
credManager := cred.GetCredManager(organization.PasswordType)
|
||||
if credManager == nil {
|
||||
// If no credential manager is available, we can't compare passwords
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the new password is the same as the current password
|
||||
// Try with both organization salt and user salt (like CheckPassword function does)
|
||||
if credManager.IsPasswordCorrect(newPassword, user.Password, organization.PasswordSalt) ||
|
||||
credManager.IsPasswordCorrect(newPassword, user.Password, user.PasswordSalt) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ func TestSmtpServer(provider *Provider) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
|
||||
func SendEmail(provider *Provider, title string, content string, dest []string, sender string) error {
|
||||
emailProvider := email.GetEmailProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.DisableSsl, provider.Endpoint, provider.Method, provider.HttpHeaders, provider.UserMapping, provider.IssuerUrl)
|
||||
|
||||
fromAddress := provider.ClientId2
|
||||
|
@@ -16,6 +16,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@@ -206,6 +207,115 @@ func GetPolicies(id string) ([]*xormadapter.CasbinRule, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Filter represents filter criteria with optional policy type
|
||||
type Filter struct {
|
||||
Ptype string `json:"ptype,omitempty"`
|
||||
FieldIndex *int `json:"fieldIndex,omitempty"`
|
||||
FieldValues []string `json:"fieldValues"`
|
||||
}
|
||||
|
||||
func GetFilteredPolicies(id string, ptype string, fieldIndex int, fieldValues ...string) ([]*xormadapter.CasbinRule, error) {
|
||||
enforcer, err := GetInitializedEnforcer(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var allRules [][]string
|
||||
|
||||
if len(fieldValues) == 0 {
|
||||
if ptype == "g" {
|
||||
allRules = enforcer.GetFilteredGroupingPolicy(fieldIndex)
|
||||
} else {
|
||||
allRules = enforcer.GetFilteredPolicy(fieldIndex)
|
||||
}
|
||||
} else {
|
||||
for _, value := range fieldValues {
|
||||
if ptype == "g" {
|
||||
rules := enforcer.GetFilteredGroupingPolicy(fieldIndex, value)
|
||||
allRules = append(allRules, rules...)
|
||||
} else {
|
||||
rules := enforcer.GetFilteredPolicy(fieldIndex, value)
|
||||
allRules = append(allRules, rules...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res := util.MatrixToCasbinRules(ptype, allRules)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetFilteredPoliciesMulti applies multiple filters to policies
|
||||
// Doing this in our loop is more efficient than using GetFilteredGroupingPolicy / GetFilteredPolicy which
|
||||
// iterates over all policies again and again
|
||||
func GetFilteredPoliciesMulti(id string, filters []Filter) ([]*xormadapter.CasbinRule, error) {
|
||||
// Get all policies first
|
||||
allPolicies, err := GetPolicies(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Filter policies based on multiple criteria
|
||||
var filteredPolicies []*xormadapter.CasbinRule
|
||||
if len(filters) == 0 {
|
||||
// No filters, return all policies
|
||||
return allPolicies, nil
|
||||
} else {
|
||||
for _, policy := range allPolicies {
|
||||
matchesAllFilters := true
|
||||
for _, filter := range filters {
|
||||
// Default policy type if unspecified
|
||||
if filter.Ptype == "" {
|
||||
filter.Ptype = "p"
|
||||
}
|
||||
// Always check policy type
|
||||
if policy.Ptype != filter.Ptype {
|
||||
matchesAllFilters = false
|
||||
break
|
||||
}
|
||||
|
||||
// If FieldIndex is nil, only filter via ptype (skip field-value checks)
|
||||
if filter.FieldIndex == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldIndex := *filter.FieldIndex
|
||||
// If FieldIndex is out of range, also only filter via ptype
|
||||
if fieldIndex < 0 || fieldIndex > 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
var fieldValue string
|
||||
switch fieldIndex {
|
||||
case 0:
|
||||
fieldValue = policy.V0
|
||||
case 1:
|
||||
fieldValue = policy.V1
|
||||
case 2:
|
||||
fieldValue = policy.V2
|
||||
case 3:
|
||||
fieldValue = policy.V3
|
||||
case 4:
|
||||
fieldValue = policy.V4
|
||||
case 5:
|
||||
fieldValue = policy.V5
|
||||
}
|
||||
|
||||
// When FieldIndex is provided and valid, enforce FieldValues (if any)
|
||||
if len(filter.FieldValues) > 0 && !slices.Contains(filter.FieldValues, fieldValue) {
|
||||
matchesAllFilters = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matchesAllFilters {
|
||||
filteredPolicies = append(filteredPolicies, policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPolicies, nil
|
||||
}
|
||||
|
||||
func UpdatePolicy(id string, ptype string, oldPolicy []string, newPolicy []string) (bool, error) {
|
||||
enforcer, err := GetInitializedEnforcer(id)
|
||||
if err != nil {
|
||||
|
@@ -70,6 +70,16 @@ func GetGroups(owner string) ([]*Group, error) {
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func GetGlobalGroups() ([]*Group, error) {
|
||||
groups := []*Group{}
|
||||
err := ormer.Engine.Desc("created_time").Find(&groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func GetPaginationGroups(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Group, error) {
|
||||
groups := []*Group{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
|
@@ -235,3 +235,8 @@ func (invitation *Invitation) IsInvitationCodeValid(application *Application, in
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (invitation *Invitation) GetInvitationLink(host string, application string) string {
|
||||
frontEnd, _ := getOriginFromHost(host)
|
||||
return fmt.Sprintf("%s/signup/%s?invitationCode=%s", frontEnd, application, invitation.Code)
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ type Ldap struct {
|
||||
AllowSelfSignedCert bool `xorm:"bool" json:"allowSelfSignedCert"`
|
||||
Username string `xorm:"varchar(100)" json:"username"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
BaseDn string `xorm:"varchar(100)" json:"baseDn"`
|
||||
BaseDn string `xorm:"varchar(500)" json:"baseDn"`
|
||||
Filter string `xorm:"varchar(200)" json:"filter"`
|
||||
FilterFields []string `xorm:"varchar(100)" json:"filterFields"`
|
||||
DefaultGroup string `xorm:"varchar(100)" json:"defaultGroup"`
|
||||
|
@@ -80,6 +80,7 @@ type Organization struct {
|
||||
IsProfilePublic bool `json:"isProfilePublic"`
|
||||
UseEmailAsUsername bool `json:"useEmailAsUsername"`
|
||||
EnableTour bool `json:"enableTour"`
|
||||
DisableSignin bool `json:"disableSignin"`
|
||||
IpRestriction string `json:"ipRestriction"`
|
||||
NavItems []string `xorm:"mediumtext" json:"navItems"`
|
||||
WidgetItems []string `xorm:"mediumtext" json:"widgetItems"`
|
||||
|
@@ -49,7 +49,7 @@ type Permission struct {
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
}
|
||||
|
||||
const builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
|
||||
const builtInMaxFields = 6 // Casdoor built-in adapter, use V5 to filter permission, so has 6 max field
|
||||
|
||||
func GetPermissionCount(owner, field, value string) (int64, error) {
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
|
@@ -125,10 +125,10 @@ func getPolicies(permission *Permission) [][]string {
|
||||
for _, action := range permission.Actions {
|
||||
if domainExist {
|
||||
for _, domain := range permission.Domains {
|
||||
policies = append(policies, []string{userOrRole, domain, resource, strings.ToLower(action), strings.ToLower(permission.Effect), permissionId})
|
||||
policies = append(policies, []string{userOrRole, domain, resource, action, strings.ToLower(permission.Effect), permissionId})
|
||||
}
|
||||
} else {
|
||||
policies = append(policies, []string{userOrRole, resource, strings.ToLower(action), strings.ToLower(permission.Effect), "", permissionId})
|
||||
policies = append(policies, []string{userOrRole, resource, action, strings.ToLower(permission.Effect), "", permissionId})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,15 +410,23 @@ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
|
||||
policyDefinition := strings.Split(cfg.String("policy_definition::p"), ",")
|
||||
|
||||
fieldsNum := len(policyDefinition)
|
||||
if fieldsNum > builtInAvailableField {
|
||||
return nil, fmt.Errorf("the maximum policy_definition field number cannot exceed %d, got %d", builtInAvailableField, fieldsNum)
|
||||
if fieldsNum > builtInMaxFields {
|
||||
return nil, fmt.Errorf("the maximum policy_definition field number cannot exceed %d, got %d", builtInMaxFields, fieldsNum)
|
||||
}
|
||||
|
||||
// filled empty field with "" and V5 with "permissionId"
|
||||
for i := builtInAvailableField - fieldsNum; i > 0; i-- {
|
||||
policyDefinition = append(policyDefinition, "")
|
||||
if fieldsNum == builtInMaxFields {
|
||||
sixthField := strings.TrimSpace(policyDefinition[builtInMaxFields-1])
|
||||
if sixthField != "permissionId" {
|
||||
return nil, fmt.Errorf("when adding policies with permissions, the sixth field of policy_definition must be permissionId, got %s", policyDefinition[builtInMaxFields-1])
|
||||
}
|
||||
} else {
|
||||
needFill := builtInMaxFields - fieldsNum
|
||||
for i := 0; i < needFill-1; i++ {
|
||||
policyDefinition = append(policyDefinition, "")
|
||||
}
|
||||
policyDefinition = append(policyDefinition, "permissionId")
|
||||
}
|
||||
policyDefinition = append(policyDefinition, "permissionId")
|
||||
|
||||
m, err := model.NewModelFromString(modelText)
|
||||
if err != nil {
|
||||
|
@@ -31,9 +31,11 @@ func GetDirectResources(owner string, user string, provider *Provider, prefix st
|
||||
fullPathPrefix := util.UrlJoin(provider.PathPrefix, prefix)
|
||||
objects, err := storageProvider.List(fullPathPrefix)
|
||||
for _, obj := range objects {
|
||||
name := strings.TrimPrefix(obj.Path, "/")
|
||||
name = strings.TrimPrefix(name, provider.PathPrefix+"/")
|
||||
resource := &Resource{
|
||||
Owner: owner,
|
||||
Name: strings.TrimPrefix(obj.Path, "/"),
|
||||
Name: name,
|
||||
CreatedTime: obj.LastModified.Local().Format(time.RFC3339),
|
||||
User: user,
|
||||
Provider: "",
|
||||
|
@@ -70,7 +70,13 @@ func NewSamlResponse(application *Application, user *User, host string, certific
|
||||
if application.UseEmailAsSamlNameId {
|
||||
nameIDValue = user.Email
|
||||
}
|
||||
subject.CreateElement("saml:NameID").SetText(nameIDValue)
|
||||
nameId := subject.CreateElement("saml:NameID")
|
||||
if application.UseEmailAsSamlNameId {
|
||||
nameId.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
|
||||
} else {
|
||||
nameId.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified")
|
||||
}
|
||||
nameId.SetText(nameIDValue)
|
||||
subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation")
|
||||
subjectConfirmation.CreateAttr("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer")
|
||||
subjectConfirmationData := subjectConfirmation.CreateElement("saml:SubjectConfirmationData")
|
||||
@@ -108,20 +114,46 @@ func NewSamlResponse(application *Application, user *User, host string, certific
|
||||
displayName.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
|
||||
displayName.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(user.DisplayName)
|
||||
|
||||
err := ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range application.SamlAttributes {
|
||||
role := attributes.CreateElement("saml:Attribute")
|
||||
role.CreateAttr("Name", item.Name)
|
||||
role.CreateAttr("NameFormat", item.NameFormat)
|
||||
role.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(item.Value)
|
||||
|
||||
valueList := []string{item.Value}
|
||||
if strings.Contains(item.Value, "$user.roles") {
|
||||
valueList = replaceSamlAttributeValuesWithList("$user.roles", getUserRoleNames(user), valueList)
|
||||
}
|
||||
|
||||
if strings.Contains(item.Value, "$user.permissions") {
|
||||
valueList = replaceSamlAttributeValuesWithList("$user.permissions", getUserPermissionNames(user), valueList)
|
||||
}
|
||||
|
||||
if strings.Contains(item.Value, "$user.groups") {
|
||||
valueList = replaceSamlAttributeValuesWithList("$user.groups", user.Groups, valueList)
|
||||
}
|
||||
|
||||
valueList = replaceSamlAttributeValues("$user.owner", user.Owner, valueList)
|
||||
valueList = replaceSamlAttributeValues("$user.name", user.Name, valueList)
|
||||
valueList = replaceSamlAttributeValues("$user.email", user.Email, valueList)
|
||||
valueList = replaceSamlAttributeValues("$user.id", user.Id, valueList)
|
||||
valueList = replaceSamlAttributeValues("$user.phone", user.Phone, valueList)
|
||||
|
||||
for _, value := range valueList {
|
||||
av := role.CreateElement("saml:AttributeValue")
|
||||
av.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
|
||||
av.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
av.CreateAttr("xsi:type", "xs:string").Element().SetText(value)
|
||||
}
|
||||
}
|
||||
|
||||
roles := attributes.CreateElement("saml:Attribute")
|
||||
roles.CreateAttr("Name", "Roles")
|
||||
roles.CreateAttr("NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic")
|
||||
err := ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, role := range user.Roles {
|
||||
roles.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(role.Name)
|
||||
@@ -130,6 +162,26 @@ func NewSamlResponse(application *Application, user *User, host string, certific
|
||||
return samlResponse, nil
|
||||
}
|
||||
|
||||
func replaceSamlAttributeValues(val string, replaceVal string, values []string) []string {
|
||||
newValues := []string{}
|
||||
for _, value := range values {
|
||||
newValues = append(newValues, strings.ReplaceAll(value, val, replaceVal))
|
||||
}
|
||||
|
||||
return newValues
|
||||
}
|
||||
|
||||
func replaceSamlAttributeValuesWithList(val string, replaceVals []string, values []string) []string {
|
||||
newValues := []string{}
|
||||
for _, value := range values {
|
||||
for _, rVal := range replaceVals {
|
||||
newValues = append(newValues, strings.ReplaceAll(value, val, rVal))
|
||||
}
|
||||
}
|
||||
|
||||
return newValues
|
||||
}
|
||||
|
||||
type X509Key struct {
|
||||
X509Certificate string
|
||||
PrivateKey string
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
@@ -33,6 +34,8 @@ type Claims struct {
|
||||
// the `azp` (Authorized Party) claim. Optional. See https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
Azp string `json:"azp,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
|
||||
SigninMethod string `json:"signinMethod,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@@ -153,6 +156,8 @@ type ClaimsShort struct {
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Azp string `json:"azp,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
|
||||
SigninMethod string `json:"signinMethod,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@@ -173,6 +178,8 @@ type ClaimsWithoutThirdIdp struct {
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Azp string `json:"azp,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
|
||||
SigninMethod string `json:"signinMethod,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@@ -302,6 +309,7 @@ func getShortClaims(claims Claims) ClaimsShort {
|
||||
Scope: claims.Scope,
|
||||
RegisteredClaims: claims.RegisteredClaims,
|
||||
Azp: claims.Azp,
|
||||
SigninMethod: claims.SigninMethod,
|
||||
Provider: claims.Provider,
|
||||
}
|
||||
return res
|
||||
@@ -316,6 +324,7 @@ func getClaimsWithoutThirdIdp(claims Claims) ClaimsWithoutThirdIdp {
|
||||
Scope: claims.Scope,
|
||||
RegisteredClaims: claims.RegisteredClaims,
|
||||
Azp: claims.Azp,
|
||||
SigninMethod: claims.SigninMethod,
|
||||
Provider: claims.Provider,
|
||||
}
|
||||
return res
|
||||
@@ -338,13 +347,35 @@ func getClaimsCustom(claims Claims, tokenField []string) jwt.MapClaims {
|
||||
res["tag"] = claims.Tag
|
||||
res["scope"] = claims.Scope
|
||||
res["azp"] = claims.Azp
|
||||
res["signinMethod"] = claims.SigninMethod
|
||||
res["provider"] = claims.Provider
|
||||
|
||||
for _, field := range tokenField {
|
||||
userField := userValue.FieldByName(field)
|
||||
if userField.IsValid() {
|
||||
newfield := util.SnakeToCamel(util.CamelToSnakeCase(field))
|
||||
res[newfield] = userField.Interface()
|
||||
if strings.HasPrefix(field, "Properties.") {
|
||||
/*
|
||||
Use selected properties fields as custom claims.
|
||||
Converts `Properties.my_field` to custom claim with name `my_field`.
|
||||
*/
|
||||
parts := strings.Split(field, ".")
|
||||
if len(parts) != 2 || parts[0] != "Properties" { // Either too many segments, or not properly scoped to `Properties`, so skip.
|
||||
continue
|
||||
}
|
||||
base, fieldName := parts[0], parts[1]
|
||||
mField := userValue.FieldByName(base)
|
||||
if !mField.IsValid() { // Can't find `Properties` field, so skip.
|
||||
continue
|
||||
}
|
||||
finalField := mField.MapIndex(reflect.ValueOf(fieldName))
|
||||
if finalField.IsValid() { // // Provided field within `Properties` exists, add claim.
|
||||
res[fieldName] = finalField.Interface()
|
||||
}
|
||||
|
||||
} else { // Use selected user field as claims.
|
||||
userField := userValue.FieldByName(field)
|
||||
if userField.IsValid() {
|
||||
newfield := util.SnakeToCamel(util.CamelToSnakeCase(field))
|
||||
res[newfield] = userField.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +404,7 @@ func refineUser(user *User) *User {
|
||||
return user
|
||||
}
|
||||
|
||||
func generateJwtToken(application *Application, user *User, provider string, nonce string, scope string, host string) (string, string, string, error) {
|
||||
func generateJwtToken(application *Application, user *User, provider string, signinMethod string, nonce string, scope string, host string) (string, string, string, error) {
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
||||
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
||||
@@ -381,6 +412,14 @@ func generateJwtToken(application *Application, user *User, provider string, non
|
||||
refreshExpireTime = expireTime
|
||||
}
|
||||
|
||||
if conf.GetConfigBool("useGroupPathInToken") {
|
||||
groupPath, err := user.GetUserFullGroupPath()
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
user.Groups = groupPath
|
||||
}
|
||||
user = refineUser(user)
|
||||
|
||||
_, originBackend := getOriginFromHost(host)
|
||||
@@ -393,10 +432,11 @@ func generateJwtToken(application *Application, user *User, provider string, non
|
||||
TokenType: "access-token",
|
||||
Nonce: nonce,
|
||||
// FIXME: A workaround for custom claim by reusing `tag` in user info
|
||||
Tag: user.Tag,
|
||||
Scope: scope,
|
||||
Azp: application.ClientId,
|
||||
Provider: provider,
|
||||
Tag: user.Tag,
|
||||
Scope: scope,
|
||||
Azp: application.ClientId,
|
||||
Provider: provider,
|
||||
SigninMethod: signinMethod,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: originBackend,
|
||||
Subject: user.Id,
|
||||
|
@@ -136,7 +136,7 @@ func CheckOAuthLogin(clientId string, responseType string, redirectUri string, s
|
||||
return "", application, nil
|
||||
}
|
||||
|
||||
func GetOAuthCode(userId string, clientId string, provider string, responseType string, redirectUri string, scope string, state string, nonce string, challenge string, host string, lang string) (*Code, error) {
|
||||
func GetOAuthCode(userId string, clientId string, provider string, signinMethod string, responseType string, redirectUri string, scope string, state string, nonce string, challenge string, host string, lang string) (*Code, error) {
|
||||
user, err := GetUser(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -171,7 +171,7 @@ func GetOAuthCode(userId string, clientId string, provider string, responseType
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, provider, nonce, scope, host)
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, provider, signinMethod, nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -379,7 +379,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", "", scope, host)
|
||||
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", "", "", scope, host)
|
||||
if err != nil {
|
||||
return &TokenError{
|
||||
Error: EndpointError,
|
||||
@@ -558,7 +558,7 @@ func GetPasswordToken(application *Application, username string, password string
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", scope, host)
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
@@ -604,7 +604,7 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
|
||||
Type: "application",
|
||||
}
|
||||
|
||||
accessToken, _, tokenName, err := generateJwtToken(application, nullUser, "", "", scope, host)
|
||||
accessToken, _, tokenName, err := generateJwtToken(application, nullUser, "", "", "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
@@ -668,7 +668,7 @@ func GetTokenByUser(application *Application, user *User, scope string, nonce st
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", nonce, scope, host)
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -775,7 +775,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", "", host)
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", "", "", host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
|
@@ -510,6 +510,8 @@ func GetUserByPhone(owner string, phone string) (*User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
phone = util.GetSeperatedPhone(phone)
|
||||
|
||||
user := User{Owner: owner, Phone: phone}
|
||||
existed, err := ormer.Engine.Get(&user)
|
||||
if err != nil {
|
||||
@@ -528,6 +530,8 @@ func GetUserByPhoneOnly(phone string) (*User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
phone = util.GetSeperatedPhone(phone)
|
||||
|
||||
user := User{Phone: phone}
|
||||
existed, err := ormer.Engine.Get(&user)
|
||||
if err != nil {
|
||||
@@ -1331,6 +1335,56 @@ func (user *User) CheckUserFace(faceIdImage []string, provider *Provider) (bool,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (user *User) GetUserFullGroupPath() ([]string, error) {
|
||||
if len(user.Groups) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var orgGroups []*Group
|
||||
orgGroups, err := GetGroups(user.Owner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupMap := make(map[string]Group)
|
||||
for _, group := range orgGroups {
|
||||
groupMap[group.Name] = *group
|
||||
}
|
||||
|
||||
var groupFullPath []string
|
||||
|
||||
for _, groupId := range user.Groups {
|
||||
_, groupName := util.GetOwnerAndNameFromIdNoCheck(groupId)
|
||||
group, ok := groupMap[groupName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
groupPath := groupName
|
||||
|
||||
curGroup, ok := groupMap[group.ParentId]
|
||||
if !ok {
|
||||
return []string{}, fmt.Errorf("group:Group %s not exist", group.ParentId)
|
||||
}
|
||||
for {
|
||||
groupPath = util.GetId(curGroup.Name, groupPath)
|
||||
if curGroup.IsTopGroup {
|
||||
break
|
||||
}
|
||||
|
||||
curGroup, ok = groupMap[curGroup.ParentId]
|
||||
if !ok {
|
||||
return []string{}, fmt.Errorf("group:Group %s not exist", curGroup.ParentId)
|
||||
}
|
||||
}
|
||||
|
||||
groupPath = util.GetId(curGroup.Owner, groupPath)
|
||||
groupFullPath = append(groupFullPath, groupPath)
|
||||
}
|
||||
|
||||
return groupFullPath, nil
|
||||
}
|
||||
|
||||
func GenerateIdForNewUser(application *Application) (string, error) {
|
||||
if application == nil || application.GetSignupItemRule("ID") != "Incremental" {
|
||||
return util.GenerateId(), nil
|
||||
|
@@ -80,7 +80,8 @@ func GetUserByFields(organization string, field string) (*User, error) {
|
||||
}
|
||||
|
||||
// check phone
|
||||
user, err = GetUserByField(organization, "phone", field)
|
||||
phone := util.GetSeperatedPhone(field)
|
||||
user, err = GetUserByField(organization, "phone", phone)
|
||||
if user != nil || err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -247,6 +248,20 @@ func SetUserOAuthProperties(organization *Organization, user *User, providerType
|
||||
return UpdateUserForAllFields(user.GetId(), user)
|
||||
}
|
||||
|
||||
func getUserRoleNames(user *User) (res []string) {
|
||||
for _, role := range user.Roles {
|
||||
res = append(res, role.Name)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func getUserPermissionNames(user *User) (res []string) {
|
||||
for _, permission := range user.Permissions {
|
||||
res = append(res, permission.Name)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func ClearUserOAuthProperties(user *User, providerType string) (bool, error) {
|
||||
for k := range user.Properties {
|
||||
prefix := fmt.Sprintf("oauth_%s_", providerType)
|
||||
|
@@ -129,7 +129,7 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
|
||||
return err
|
||||
}
|
||||
|
||||
err = SendEmail(provider, title, content, dest, sender)
|
||||
err = SendEmail(provider, title, content, []string{dest}, sender)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -91,7 +91,7 @@ func getObject(ctx *context.Context) (string, string, error) {
|
||||
|
||||
return "", "", nil
|
||||
} else {
|
||||
if path == "/api/add-policy" || path == "/api/remove-policy" || path == "/api/update-policy" {
|
||||
if path == "/api/add-policy" || path == "/api/remove-policy" || path == "/api/update-policy" || path == "/api/send-invitation" {
|
||||
id := ctx.Input.Query("id")
|
||||
if id != "" {
|
||||
return util.GetOwnerAndNameFromIdWithError(id)
|
||||
|
@@ -102,7 +102,12 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
userId = ctx.Input.Query("username")
|
||||
password := ctx.Input.Query("password")
|
||||
if userId != "" && password != "" && ctx.Input.Query("grant_type") == "" {
|
||||
owner, name := util.GetOwnerAndNameFromId(userId)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
responseError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.CheckUserPassword(owner, name, password, "en")
|
||||
if err != nil {
|
||||
responseError(ctx, err.Error())
|
||||
|
@@ -102,6 +102,7 @@ func initAPI() {
|
||||
beego.Router("/api/add-invitation", &controllers.ApiController{}, "POST:AddInvitation")
|
||||
beego.Router("/api/delete-invitation", &controllers.ApiController{}, "POST:DeleteInvitation")
|
||||
beego.Router("/api/verify-invitation", &controllers.ApiController{}, "GET:VerifyInvitation")
|
||||
beego.Router("/api/send-invitation", &controllers.ApiController{}, "POST:SendInvitation")
|
||||
|
||||
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
||||
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
||||
@@ -160,6 +161,7 @@ func initAPI() {
|
||||
beego.Router("/api/add-adapter", &controllers.ApiController{}, "POST:AddAdapter")
|
||||
beego.Router("/api/delete-adapter", &controllers.ApiController{}, "POST:DeleteAdapter")
|
||||
beego.Router("/api/get-policies", &controllers.ApiController{}, "GET:GetPolicies")
|
||||
beego.Router("/api/get-filtered-policies", &controllers.ApiController{}, "POST:GetFilteredPolicies")
|
||||
beego.Router("/api/update-policy", &controllers.ApiController{}, "POST:UpdatePolicy")
|
||||
beego.Router("/api/add-policy", &controllers.ApiController{}, "POST:AddPolicy")
|
||||
beego.Router("/api/remove-policy", &controllers.ApiController{}, "POST:RemovePolicy")
|
||||
|
@@ -89,7 +89,7 @@ func fastAutoSignin(ctx *context.Context) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
code, err := object.GetOAuthCode(userId, clientId, "", responseType, redirectUri, scope, state, nonce, codeChallenge, ctx.Request.Host, getAcceptLanguage(ctx))
|
||||
code, err := object.GetOAuthCode(userId, clientId, "", "autoSignin", responseType, redirectUri, scope, state, nonce, codeChallenge, ctx.Request.Host, getAcceptLanguage(ctx))
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if code.Message != "" {
|
||||
|
1169
swagger/swagger.json
1169
swagger/swagger.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nyaruka/phonenumbers"
|
||||
)
|
||||
|
||||
func ParseInt(s string) int {
|
||||
@@ -278,6 +279,19 @@ func GetMaskedPhone(phone string) string {
|
||||
return rePhone.ReplaceAllString(phone, "$1****$2")
|
||||
}
|
||||
|
||||
func GetSeperatedPhone(phone string) string {
|
||||
if strings.HasPrefix(phone, "+") {
|
||||
phoneNumberParsed, err := phonenumbers.Parse(phone, "")
|
||||
if err != nil {
|
||||
return phone
|
||||
}
|
||||
|
||||
phone = fmt.Sprintf("%d", phoneNumberParsed.GetNationalNumber())
|
||||
}
|
||||
|
||||
return phone
|
||||
}
|
||||
|
||||
func GetMaskedEmail(email string) string {
|
||||
if email == "" {
|
||||
return ""
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"@web3-onboard/gnosis": "^2.1.10",
|
||||
"@web3-onboard/infinity-wallet": "^2.0.4",
|
||||
"@web3-onboard/injected-wallets": "^2.10.4",
|
||||
"@web3-onboard/phantom": "^2.1.1",
|
||||
"@web3-onboard/react": "^2.8.10",
|
||||
"@web3-onboard/sequence": "^2.0.8",
|
||||
"@web3-onboard/taho": "^2.0.5",
|
||||
|
@@ -468,6 +468,16 @@ class ApplicationEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Order"), i18next.t("application:Order - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber style={{width: "150px"}} value={this.state.application.order} min={0} step={1} precision={0} addonAfter="" onChange={value => {
|
||||
this.updateApplicationField("order", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Token expire"), i18next.t("application:Token expire - Tooltip"))} :
|
||||
@@ -543,6 +553,16 @@ class ApplicationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Disable signin"), i18next.t("application:Disable signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.disableSignin} onChange={checked => {
|
||||
this.updateApplicationField("disableSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Signin session"), i18next.t("application:Enable signin session - Tooltip"))} :
|
||||
|
@@ -41,6 +41,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
logo: `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`,
|
||||
enablePassword: true,
|
||||
enableSignUp: true,
|
||||
disableSignin: false,
|
||||
enableSigninSession: false,
|
||||
enableCodeSignin: false,
|
||||
enableSamlCompress: false,
|
||||
@@ -112,6 +113,34 @@ class ApplicationListPage extends BaseListPage {
|
||||
});
|
||||
}
|
||||
|
||||
copyApplication(i) {
|
||||
const original = this.state.data[i];
|
||||
const randomSuffix = Setting.getRandomName();
|
||||
const newName = `${original.name}_${randomSuffix}`;
|
||||
|
||||
const copiedApplication = {
|
||||
...original,
|
||||
name: newName,
|
||||
createdTime: moment().format(),
|
||||
displayName: "Copy Application - " + newName,
|
||||
clientId: "",
|
||||
clientSecret: "",
|
||||
};
|
||||
|
||||
ApplicationBackend.addApplication(copiedApplication)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/applications/${copiedApplication.organization}/${newName}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully copied"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to copy")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(applications) {
|
||||
const columns = [
|
||||
{
|
||||
@@ -236,12 +265,13 @@ class ApplicationListPage extends BaseListPage {
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: "",
|
||||
key: "op",
|
||||
width: "170px",
|
||||
width: "230px",
|
||||
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(`/applications/${record.organization}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => this.copyApplication(index)}>{i18next.t("general:Copy")}</Button>
|
||||
<PopconfirmModal
|
||||
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteApplication(index)}
|
||||
|
@@ -42,10 +42,11 @@ class BaseListPage extends React.Component {
|
||||
handleOrganizationChange = () => {
|
||||
this.setState({
|
||||
organizationName: this.props.match?.params.organizationName || Setting.getRequestOrganization(this.props.account),
|
||||
},
|
||||
() => {
|
||||
const {pagination} = this.state;
|
||||
this.fetch({pagination});
|
||||
});
|
||||
|
||||
const {pagination} = this.state;
|
||||
this.fetch({pagination});
|
||||
};
|
||||
|
||||
handleTourChange = () => {
|
||||
|
@@ -13,7 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select} from "antd";
|
||||
import {Button, Card, Col, Input, InputNumber, Modal, Row, Select, Table} from "antd";
|
||||
import {CopyOutlined} from "@ant-design/icons";
|
||||
import * as InvitationBackend from "./backend/InvitationBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||
@@ -36,6 +37,7 @@ class InvitationEditPage extends React.Component {
|
||||
applications: [],
|
||||
groups: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
sendLoading: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -122,6 +124,35 @@ class InvitationEditPage extends React.Component {
|
||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
}
|
||||
|
||||
renderSendEmailModal() {
|
||||
const emailColumns = [
|
||||
{title: "email", dataIndex: "email"},
|
||||
];
|
||||
const emails = this.state.emails?.split("\n")?.filter(email => Setting.isValidEmail(email));
|
||||
const emailData = emails?.map((email) => {return {email: email};});
|
||||
|
||||
return <Modal title={i18next.t("general:Send")}
|
||||
style={{height: "800px"}}
|
||||
open={this.state.showSendModal}
|
||||
closable
|
||||
footer={[
|
||||
<Button key={1} loading={this.state.sendLoading} type="primary"
|
||||
onClick={() => {
|
||||
this.setState({sendLoading: true});
|
||||
InvitationBackend.sendInvitation(this.state.invitation, emails).then(() => {
|
||||
this.setState({sendLoading: false});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully sent"));
|
||||
}).catch(err => Setting.showMessage("success", err.message));
|
||||
}}>{i18next.t("general:Send")}</Button>,
|
||||
]}
|
||||
onCancel={() => {this.setState({showSendModal: false});}}>
|
||||
<div >
|
||||
<p>You will send invitation email to:</p>
|
||||
<Table showHeader={false} columns={emailColumns} dataSource={emailData} size={"small"}></Table>
|
||||
</div>
|
||||
</Modal>;
|
||||
}
|
||||
|
||||
renderInvitation() {
|
||||
const isCreatedByPlan = this.state.invitation.tag === "auto_created_invitation_for_plan";
|
||||
return (
|
||||
@@ -130,9 +161,6 @@ class InvitationEditPage extends React.Component {
|
||||
{this.state.mode === "add" ? i18next.t("invitation:New Invitation") : i18next.t("invitation:Edit Invitation")}
|
||||
<Button onClick={() => this.submitInvitationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitInvitationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} onClick={_ => this.copySignupLink()}>
|
||||
{i18next.t("application:Copy signup page URL")}
|
||||
</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteInvitation()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
@@ -192,6 +220,26 @@ class InvitationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={_ => this.copySignupLink()}>
|
||||
{i18next.t("application:Copy signup page URL")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{i18next.t("general:Send")}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input.TextArea autoSize={{minRows: 3, maxRows: 10}} value={this.state.emails} onChange={(value) => {
|
||||
this.setState({emails: value.target.value});
|
||||
}}></Input.TextArea>
|
||||
<Button type="primary" style={{marginTop: "20px"}} onClick={() => this.setState({showSendModal: true})}>{i18next.t("general:Send")}</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("invitation:Quota"), i18next.t("invitation:Quota - Tooltip"))} :
|
||||
@@ -331,15 +379,13 @@ class InvitationEditPage extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.showSendModal ? this.renderSendEmailModal() : null}
|
||||
{
|
||||
this.state.invitation !== null ? this.renderInvitation() : null
|
||||
}
|
||||
<div style={{marginTop: "20px", marginLeft: "40px"}}>
|
||||
<Button size="large" onClick={() => this.submitInvitationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} type="primary" size="large" onClick={() => this.submitInvitationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} size="large" onClick={_ => this.copySignupLink()}>
|
||||
{i18next.t("application:Copy signup page URL")}
|
||||
</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} size="large" onClick={() => this.deleteInvitation()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -561,6 +561,16 @@ class OrganizationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Disable signin"), i18next.t("application:Disable signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.organization.disableSignin} onChange={checked => {
|
||||
this.updateOrganizationField("disableSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Navbar items"), i18next.t("organization:Navbar items - Tooltip"))} :
|
||||
|
@@ -49,6 +49,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
enableSoftDeletion: false,
|
||||
isProfilePublic: true,
|
||||
enableTour: true,
|
||||
disableSignin: false,
|
||||
mfaRememberInHours: DefaultMfaRememberInHours,
|
||||
accountItems: [
|
||||
{name: "Organization", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
|
@@ -174,7 +174,11 @@ class ProviderEditPage extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
provider.userMapping[key] = value;
|
||||
if (value === "") {
|
||||
delete provider.userMapping[key];
|
||||
} else {
|
||||
provider.userMapping[key] = value;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
provider: provider,
|
||||
@@ -593,6 +597,7 @@ class ProviderEditPage extends React.Component {
|
||||
this.updateProviderField("disableSsl", false);
|
||||
this.updateProviderField("title", "Casdoor Verification Code");
|
||||
this.updateProviderField("content", Setting.getDefaultHtmlEmailContent());
|
||||
this.updateProviderField("metadata", Setting.getDefaultInvitationHtmlEmailContent());
|
||||
this.updateProviderField("receiver", this.props.account.email);
|
||||
} else if (value === "SMS") {
|
||||
this.updateProviderField("type", "Twilio SMS");
|
||||
@@ -878,9 +883,17 @@ class ProviderEditPage extends React.Component {
|
||||
{this.getClientSecret2Label(this.state.provider)} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.clientSecret2} onChange={e => {
|
||||
this.updateProviderField("clientSecret2", e.target.value);
|
||||
}} />
|
||||
{
|
||||
(this.state.provider.category === "OAuth" && this.state.provider.type === "Apple") ? (
|
||||
<TextArea autoSize={{minRows: 1, maxRows: 20}} value={this.state.provider.clientSecret2} onChange={e => {
|
||||
this.updateProviderField("clientSecret2", e.target.value);
|
||||
}} />
|
||||
) : (
|
||||
<Input value={this.state.provider.clientSecret2} onChange={e => {
|
||||
this.updateProviderField("clientSecret2", e.target.value);
|
||||
}} />
|
||||
)
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
@@ -1259,6 +1272,42 @@ class ProviderEditPage extends React.Component {
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(`${i18next.t("provider:Email content")}-${i18next.t("general:Invitations")}`, i18next.t("provider:Email content - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => this.updateProviderField("metadata", "You have invited to join Casdoor. Here is your invitation code: %s, please enter in 5 minutes. Or click %link to signup")} >
|
||||
{i18next.t("provider:Reset to Default Text")}
|
||||
</Button>
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary" onClick={() => this.updateProviderField("metadata", Setting.getDefaultInvitationHtmlEmailContent())} >
|
||||
{i18next.t("provider:Reset to Default HTML")}
|
||||
</Button>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{height: "300px", margin: "10px"}}>
|
||||
<Editor
|
||||
value={this.state.provider.metadata}
|
||||
fillHeight
|
||||
dark
|
||||
lang="html"
|
||||
onChange={value => {
|
||||
this.updateProviderField("metadata", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={1} />
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{margin: "10px"}}>
|
||||
<div dangerouslySetInnerHTML={{__html: this.state.provider.metadata.replace("%code", "123456")}} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Test Email"), i18next.t("provider:Test Email - Tooltip"))} :
|
||||
|
@@ -60,6 +60,7 @@ export const Countries = [
|
||||
{label: "فارسی", key: "fa", country: "IR", alt: "فارسی"},
|
||||
{label: "Čeština", key: "cs", country: "CZ", alt: "Čeština"},
|
||||
{label: "Slovenčina", key: "sk", country: "SK", alt: "Slovenčina"},
|
||||
{label: "Azərbaycan dili", key: "az", country: "AZ", alt: "Azərbaycan dili"},
|
||||
];
|
||||
|
||||
export function getThemeData(organization, application) {
|
||||
@@ -156,7 +157,7 @@ export const OtherProviderInfo = {
|
||||
url: "https://control.msg91.com/app/",
|
||||
},
|
||||
"OSON SMS": {
|
||||
logo: "https://osonsms.com/images/osonsms-logo.svg",
|
||||
logo: `${StaticBaseUrl}/img/social_osonsms.svg`,
|
||||
url: "https://osonsms.com/",
|
||||
},
|
||||
"Custom HTTP SMS": {
|
||||
@@ -204,7 +205,7 @@ export const OtherProviderInfo = {
|
||||
url: "https://aws.amazon.com/s3",
|
||||
},
|
||||
"MinIO": {
|
||||
logo: "https://min.io/resources/img/logo.svg",
|
||||
logo: `${StaticBaseUrl}/img/social_minio.png`,
|
||||
url: "https://min.io/",
|
||||
},
|
||||
"Aliyun OSS": {
|
||||
@@ -1296,6 +1297,9 @@ export function renderSignupLink(application, text) {
|
||||
} else {
|
||||
if (application.signupUrl === "") {
|
||||
url = `/signup/${application.name}`;
|
||||
if (application.isShared) {
|
||||
url = `/signup/${application.name}-org-${application.organization}`;
|
||||
}
|
||||
} else {
|
||||
url = application.signupUrl;
|
||||
}
|
||||
@@ -1644,6 +1648,48 @@ export function getDefaultHtmlEmailContent() {
|
||||
</html>`;
|
||||
}
|
||||
|
||||
export function getDefaultInvitationHtmlEmailContent() {
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Invitation Code Email</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; }
|
||||
.email-container { width: 600px; margin: 0 auto; }
|
||||
.header { text-align: center; }
|
||||
.code { font-size: 24px; margin: 20px 0; text-align: center; }
|
||||
.footer { font-size: 12px; text-align: center; margin-top: 50px; }
|
||||
.footer a { color: #000; text-decoration: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-container">
|
||||
<div class="header">
|
||||
<h3>Casbin Organization</h3>
|
||||
<img src="${StaticBaseUrl}/img/casdoor-logo_1185x256.png" alt="Casdoor Logo" width="300">
|
||||
</div>
|
||||
<p>You have been invited into Casdoor</p>
|
||||
<div class="code">
|
||||
%code
|
||||
</div>
|
||||
<reset-link>
|
||||
<div class="link">
|
||||
Or click this <a href="%link">link</a> to signup
|
||||
</div>
|
||||
</reset-link>
|
||||
<p>Thanks</p>
|
||||
<p>Casbin Team</p>
|
||||
<hr>
|
||||
<div class="footer">
|
||||
<p>Casdoor is a brand operated by Casbin organization. For more info please refer to <a href="https://casdoor.org">https://casdoor.org</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
export function getCurrencyText(product) {
|
||||
if (product?.currency === "USD") {
|
||||
return i18next.t("currency:USD");
|
||||
|
@@ -326,7 +326,7 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="multiple" style={{width: "100%"}} disabled={disabled} value={this.state.user.groups ?? []} onChange={(value => {
|
||||
if (this.state.groups?.filter(group => value.includes(group.name))
|
||||
if (this.state.groups?.filter(group => value.includes(`${group.owner}/${group.name}`))
|
||||
.filter(group => group.type === "Physical").length > 1) {
|
||||
Setting.showMessage("error", i18next.t("general:You can only select one physical group"));
|
||||
return;
|
||||
@@ -1117,6 +1117,32 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "First name") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:First name"), i18next.t("general:First name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Input value={this.state.user.firstName} onChange={e => {
|
||||
this.updateUserField("firstName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "Last name") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Last name"), i18next.t("general:Last name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Input value={this.state.user.lastName} onChange={e => {
|
||||
this.updateUserField("lastName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,7 @@ const applicationTemplate = {
|
||||
logo: `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`,
|
||||
enablePassword: true,
|
||||
enableSignUp: true,
|
||||
disableSignin: false,
|
||||
enableSigninSession: false,
|
||||
enableCodeSignin: false,
|
||||
enableSamlCompress: false,
|
||||
|
@@ -39,12 +39,14 @@ import {GoogleOneTapLoginVirtualButton} from "./GoogleLoginButton";
|
||||
import * as ProviderButton from "./ProviderButton";
|
||||
import {createFormAndSubmit, goToLink} from "../Setting";
|
||||
import WeChatLoginPanel from "./WeChatLoginPanel";
|
||||
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
|
||||
const FaceRecognitionCommonModal = lazy(() => import("../common/modal/FaceRecognitionCommonModal"));
|
||||
const FaceRecognitionModal = lazy(() => import("../common/modal/FaceRecognitionModal"));
|
||||
|
||||
class LoginPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.captchaRef = React.createRef();
|
||||
this.state = {
|
||||
classes: props,
|
||||
type: props.type,
|
||||
@@ -465,6 +467,7 @@ class LoginPage extends React.Component {
|
||||
login(values) {
|
||||
// here we are supposed to determine whether Casdoor is working as an OAuth server or CAS server
|
||||
values["language"] = this.state.userLang ?? "";
|
||||
const usedCaptcha = this.state.captchaValues !== undefined;
|
||||
if (this.state.type === "cas") {
|
||||
// CAS
|
||||
const casParams = Util.getCasParameters();
|
||||
@@ -491,6 +494,9 @@ class LoginPage extends React.Component {
|
||||
Setting.checkLoginMfa(res, values, casParams, loginHandler, this);
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
|
||||
if (usedCaptcha) {
|
||||
this.captchaRef.current?.loadCaptcha?.();
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setState({loginLoading: false});
|
||||
@@ -564,6 +570,9 @@ class LoginPage extends React.Component {
|
||||
Setting.checkLoginMfa(res, values, oAuthParams, loginHandler, this);
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
|
||||
if (usedCaptcha) {
|
||||
this.captchaRef.current?.loadCaptcha?.();
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setState({loginLoading: false});
|
||||
@@ -595,6 +604,32 @@ class LoginPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
switchLoginOrganization(name) {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
const clientId = searchParams.get("client_id");
|
||||
if (clientId) {
|
||||
const clientIdSplited = clientId.split("-org-");
|
||||
searchParams.set("client_id", `${clientIdSplited[0]}-org-${name}`);
|
||||
|
||||
Setting.goToLink(`/login/oauth/authorize?${searchParams.toString()}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const application = this.getApplicationObj();
|
||||
if (window.location.pathname.startsWith("/login/saml/authorize")) {
|
||||
Setting.goToLink(`/login/saml/authorize/${name}/${application.name}-org-${name}?${searchParams.toString()}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.location.pathname.startsWith("/cas")) {
|
||||
Setting.goToLink(`/cas/${application.name}-org-${name}/${name}/login?${searchParams.toString()}`);
|
||||
return;
|
||||
}
|
||||
searchParams.set("orgChoiceMode", "None");
|
||||
Setting.goToLink(`/login/${name}?${searchParams.toString()}`);
|
||||
}
|
||||
|
||||
renderFormItem(application, signinItem) {
|
||||
if (!signinItem.visible && signinItem.name !== "Forgot password?") {
|
||||
return null;
|
||||
@@ -648,6 +683,65 @@ class LoginPage extends React.Component {
|
||||
)
|
||||
;
|
||||
} else if (signinItem.name === "Username") {
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return (<WeChatLoginPanel application={application} loginMethod={this.state.loginMethod} />);
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "verificationCodePhone") {
|
||||
return <Form.Item className="signin-phone" required={true}>
|
||||
<Input.Group compact>
|
||||
<Form.Item
|
||||
name="countryCode"
|
||||
noStyle
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: i18next.t("signup:Please select your country code!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CountryCodeSelect
|
||||
style={{width: "35%"}}
|
||||
countryCodes={this.getApplicationObj().organizationObj.countryCodes}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="username"
|
||||
dependencies={["countryCode"]}
|
||||
noStyle
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: i18next.t("signup:Please input your phone number!"),
|
||||
},
|
||||
({getFieldValue}) => ({
|
||||
validator: (_, value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (value && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
|
||||
this.setState({validEmailOrPhone: false});
|
||||
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
|
||||
}
|
||||
|
||||
this.setState({validEmailOrPhone: true});
|
||||
return Promise.resolve();
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<Input
|
||||
className="signup-phone-input"
|
||||
placeholder={signinItem.placeholder}
|
||||
style={{width: "65%", textAlign: "left"}}
|
||||
onChange={e => this.setState({username: e.target.value})}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Input.Group>
|
||||
</Form.Item>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={resultItemKey}>
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.customCss?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
@@ -750,6 +844,9 @@ class LoginPage extends React.Component {
|
||||
} else if (signinItem.name === "Agreement") {
|
||||
return AgreementModal.isAgreementRequired(application) ? AgreementModal.renderAgreementFormItem(application, true, {}, this) : null;
|
||||
} else if (signinItem.name === "Login button") {
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Form.Item key={resultItemKey} className="login-button-box">
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.customCss?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
@@ -848,6 +945,17 @@ class LoginPage extends React.Component {
|
||||
{this.renderFooter(application, signinItem)}
|
||||
</div>
|
||||
);
|
||||
} else if (signinItem.name === "Select organization") {
|
||||
return (
|
||||
<Form.Item>
|
||||
<div key={resultItemKey} style={{width: "100%"}} className="login-organization-select">
|
||||
<OrganizationSelect style={{width: "100%"}} initValue={application.organization}
|
||||
onSelect={(value) => {
|
||||
this.switchLoginOrganization(value);
|
||||
}} />
|
||||
</div>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -896,10 +1004,6 @@ class LoginPage extends React.Component {
|
||||
loginWidth += 10;
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return (<WeChatLoginPanel application={application} renderFormItem={this.renderFormItem.bind(this)} loginMethod={this.state.loginMethod} loginWidth={loginWidth} renderMethodChoiceBox={this.renderMethodChoiceBox.bind(this)} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="normal_login"
|
||||
@@ -1028,6 +1132,7 @@ class LoginPage extends React.Component {
|
||||
}}
|
||||
onCancel={() => this.setState({openCaptchaModal: false, loginLoading: false})}
|
||||
isCurrentProvider={true}
|
||||
innerRef={this.captchaRef}
|
||||
/>;
|
||||
}
|
||||
|
||||
@@ -1083,11 +1188,13 @@ class LoginPage extends React.Component {
|
||||
{i18next.t("login:Continue with")} :
|
||||
</div>
|
||||
<br />
|
||||
<SelfLoginButton account={this.props.account} onClick={() => {
|
||||
<div onClick={() => {
|
||||
const values = {};
|
||||
values["application"] = application.name;
|
||||
this.login(values);
|
||||
}} />
|
||||
}}>
|
||||
<SelfLoginButton account={this.props.account} />
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div style={{fontSize: 16, textAlign: "left"}}>
|
||||
@@ -1109,8 +1216,7 @@ class LoginPage extends React.Component {
|
||||
.then(res => res.json())
|
||||
.then((credentialRequestOptions) => {
|
||||
if ("status" in credentialRequestOptions) {
|
||||
Setting.showMessage("error", credentialRequestOptions.msg);
|
||||
throw credentialRequestOptions.status.msg;
|
||||
return Promise.reject(new Error(credentialRequestOptions.msg));
|
||||
}
|
||||
credentialRequestOptions.publicKey.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.publicKey.challenge);
|
||||
|
||||
@@ -1169,7 +1275,7 @@ class LoginPage extends React.Component {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}${error}`);
|
||||
});
|
||||
}).catch(error => {
|
||||
Setting.showMessage("error", `${error}`);
|
||||
Setting.showMessage("error", `${error.message}`);
|
||||
}).finally(() => {
|
||||
this.setState({
|
||||
loginLoading: false,
|
||||
@@ -1240,6 +1346,7 @@ class LoginPage extends React.Component {
|
||||
[generateItemKey("WebAuthn", "None"), {label: i18next.t("login:WebAuthn"), key: "webAuthn"}],
|
||||
[generateItemKey("LDAP", "None"), {label: i18next.t("login:LDAP"), key: "ldap"}],
|
||||
[generateItemKey("Face ID", "None"), {label: i18next.t("login:Face ID"), key: "faceId"}],
|
||||
[generateItemKey("WeChat", "Tab"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
[generateItemKey("WeChat", "None"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
]);
|
||||
|
||||
@@ -1404,6 +1511,8 @@ class LoginPage extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const wechatSigninMethods = application.signinMethods?.filter(method => method.name === "WeChat" && method.rule === "Login page");
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CustomGithubCorner />
|
||||
@@ -1421,6 +1530,15 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
wechatSigninMethods?.length > 0 ? (<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||
<div>
|
||||
<h3 style={{textAlign: "center", width: 320}}>{i18next.t("provider:Please use WeChat to scan the QR code and follow the official account for sign in")}</h3>
|
||||
<WeChatLoginPanel application={application} loginMethod={this.state.loginMethod} />
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
@@ -392,7 +392,11 @@ export function getAuthUrl(application, provider, method, code) {
|
||||
let redirectUri = `${redirectOrigin}/callback`;
|
||||
let scope = authInfo[provider.type].scope;
|
||||
const isShortState = (provider.type === "WeChat" && navigator.userAgent.includes("MicroMessenger")) || (provider.type === "Twitter");
|
||||
const state = Util.getStateFromQueryParams(application.name, provider.name, method, isShortState);
|
||||
let applicationName = application.name;
|
||||
if (application?.isShared) {
|
||||
applicationName = `${application.name}-org-${application.organization}`;
|
||||
}
|
||||
const state = Util.getStateFromQueryParams(applicationName, provider.name, method, isShortState);
|
||||
const codeChallenge = "P3S-a7dr8bgM4bF6vOyiKkKETDl16rcAzao9F8UIL1Y"; // SHA256(Base64-URL-encode("casdoor-verifier"))
|
||||
|
||||
if (provider.type === "AzureAD") {
|
||||
|
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import React, {memo} from "react";
|
||||
import {createButton} from "react-social-login-buttons";
|
||||
|
||||
class SelfLoginButton extends React.Component {
|
||||
@@ -44,4 +44,4 @@ class SelfLoginButton extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default SelfLoginButton;
|
||||
export default memo(SelfLoginButton);
|
||||
|
@@ -364,6 +364,40 @@ class SignupPage extends React.Component {
|
||||
<Input className="signup-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "First name" && this.state?.displayNameRule !== "First, last") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="firstName"
|
||||
className="signup-first-name"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:First name")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: i18next.t("signup:Please input your first name!"),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input className="signup-first-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Last name" && this.state?.displayNameRule !== "First, last") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="lastName"
|
||||
className="signup-last-name"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:Last name")}
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
message: i18next.t("signup:Please input your last name!"),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input className="signup-last-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Affiliation") {
|
||||
return (
|
||||
<Form.Item
|
||||
@@ -776,6 +810,12 @@ class SignupPage extends React.Component {
|
||||
this.form.current?.setFieldValue("invitationCode", this.state.invitationCode);
|
||||
}
|
||||
}
|
||||
|
||||
const displayNameItem = application.signupItems?.find(item => item.name === "Display name");
|
||||
if (displayNameItem && !this.state.displayNameRule) {
|
||||
this.setState({displayNameRule: displayNameItem.rule});
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
{...formItemLayout}
|
||||
|
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Alert, Button, Modal, Result} from "antd";
|
||||
import {Alert, Button, Modal, QRCode, Result} from "antd";
|
||||
import i18next from "i18next";
|
||||
import {getWechatMessageEvent} from "./AuthBackend";
|
||||
import * as Setting from "../Setting";
|
||||
@@ -217,7 +217,7 @@ export async function WechatOfficialAccountModal(application, provider, method)
|
||||
title: i18next.t("provider:Please use WeChat to scan the QR code and follow the official account for sign in"),
|
||||
content: (
|
||||
<div style={{marginRight: "34px"}}>
|
||||
<img src = {"data:image/png;base64," + res.data} alt="Wechat QR code" style={{width: "100%"}} />
|
||||
<QRCode style={{padding: "20px", margin: "auto"}} bordered={false} value={res.data} size={230} />
|
||||
</div>
|
||||
),
|
||||
onOk() {
|
||||
|
@@ -16,13 +16,14 @@ import React from "react";
|
||||
import * as AuthBackend from "./AuthBackend";
|
||||
import i18next from "i18next";
|
||||
import * as Util from "./Util";
|
||||
import {QRCode} from "antd";
|
||||
|
||||
class WeChatLoginPanel extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
qrCode: null,
|
||||
loading: false,
|
||||
status: "loading",
|
||||
ticket: null,
|
||||
};
|
||||
this.pollingTimer = null;
|
||||
@@ -57,47 +58,38 @@ class WeChatLoginPanel extends React.Component {
|
||||
const {application} = this.props;
|
||||
const wechatProviderItem = application?.providers?.find(p => p.provider?.type === "WeChat");
|
||||
if (wechatProviderItem) {
|
||||
this.setState({loading: true, qrCode: null, ticket: null});
|
||||
this.setState({status: "loading", qrCode: null, ticket: null});
|
||||
AuthBackend.getWechatQRCode(`${wechatProviderItem.provider.owner}/${wechatProviderItem.provider.name}`).then(res => {
|
||||
if (res.status === "ok" && res.data) {
|
||||
this.setState({qrCode: res.data, loading: false, ticket: res.data2});
|
||||
this.setState({qrCode: res.data, status: "active", ticket: res.data2});
|
||||
this.clearPolling();
|
||||
this.pollingTimer = setInterval(() => {
|
||||
Util.getEvent(application, wechatProviderItem.provider, res.data2, "signup");
|
||||
}, 1000);
|
||||
} else {
|
||||
this.setState({qrCode: null, loading: false, ticket: null});
|
||||
this.setState({qrCode: null, status: "expired", ticket: null});
|
||||
this.clearPolling();
|
||||
}
|
||||
}).catch(() => {
|
||||
this.setState({qrCode: null, loading: false, ticket: null});
|
||||
this.setState({qrCode: null, status: "expired", ticket: null});
|
||||
this.clearPolling();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {application, loginWidth = 320} = this.props;
|
||||
const {loading, qrCode} = this.state;
|
||||
const {loginWidth = 320} = this.props;
|
||||
const {status, qrCode} = this.state;
|
||||
return (
|
||||
<div style={{width: loginWidth, margin: "0 auto", textAlign: "center", marginTop: 16}}>
|
||||
{application.signinItems?.filter(item => item.name === "Logo").map(signinItem => this.props.renderFormItem(application, signinItem))}
|
||||
{this.props.renderMethodChoiceBox()}
|
||||
{application.signinItems?.filter(item => item.name === "Languages").map(signinItem => this.props.renderFormItem(application, signinItem))}
|
||||
{loading ? (
|
||||
<div style={{marginTop: 16}}>
|
||||
<span>{i18next.t("login:Loading")}</span>
|
||||
<div style={{marginTop: 2}}>
|
||||
<QRCode style={{margin: "auto", marginTop: "20px", marginBottom: "20px"}} bordered={false} status={status} value={qrCode ?? " "} size={230} />
|
||||
<div style={{marginTop: 8}}>
|
||||
<a onClick={e => {e.preventDefault(); this.fetchQrCode();}}>
|
||||
{i18next.t("login:Refresh")}
|
||||
</a>
|
||||
</div>
|
||||
) : qrCode ? (
|
||||
<div style={{marginTop: 2}}>
|
||||
<img src={`data:image/png;base64,${qrCode}`} alt="WeChat QR code" style={{width: 250, height: 250}} />
|
||||
<div style={{marginTop: 8}}>
|
||||
<a onClick={e => {e.preventDefault(); this.fetchQrCode();}}>
|
||||
{i18next.t("login:Refresh")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import frontierModule from "@web3-onboard/frontier";
|
||||
import tahoModule from "@web3-onboard/taho";
|
||||
import coinbaseModule from "@web3-onboard/coinbase";
|
||||
import gnosisModule from "@web3-onboard/gnosis";
|
||||
import phantomModule from "@web3-onboard/phantom";
|
||||
// import keystoneModule from "@web3-onboard/keystone";
|
||||
// import keepkeyModule from "@web3-onboard/keepkey";
|
||||
// import dcentModule from "@web3-onboard/dcent";
|
||||
@@ -172,6 +173,10 @@ const web3Wallets = {
|
||||
label: "Injected",
|
||||
wallet: injectedModule(),
|
||||
},
|
||||
phantom: {
|
||||
label: "Phantom",
|
||||
wallet: phantomModule(),
|
||||
},
|
||||
// sdk wallets
|
||||
coinbase: {
|
||||
label: "Coinbase",
|
||||
@@ -296,6 +301,12 @@ export function initWeb3Onboard(application, provider) {
|
||||
label: "Arbitrum",
|
||||
rpcUrl: "https://rpc.ankr.com/arbitrum",
|
||||
},
|
||||
{
|
||||
id: "0x1",
|
||||
token: "SOL",
|
||||
label: "Solana Mainnet",
|
||||
rpcUrl: "https://api.mainnet-beta.solana.com",
|
||||
},
|
||||
];
|
||||
|
||||
const appMetadata = {
|
||||
@@ -304,6 +315,7 @@ export function initWeb3Onboard(application, provider) {
|
||||
recommendedInjectedWallets: [
|
||||
{name: "MetaMask", url: "https://metamask.io"},
|
||||
{name: "Coinbase", url: "https://www.coinbase.com/wallet"},
|
||||
{name: "Phantom", url: "https://phantom.app"},
|
||||
],
|
||||
};
|
||||
|
||||
|
@@ -12,13 +12,6 @@ export const MfaVerifySmsForm = ({mfaProps, application, onFinish, method, user}
|
||||
const [dest, setDest] = React.useState("");
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values) => {
|
||||
onFinish({
|
||||
passcode: values.passcode,
|
||||
enableMfaRemember: values.enableMfaRemember,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (method === mfaAuth) {
|
||||
setDest(mfaProps.secret);
|
||||
@@ -58,7 +51,7 @@ export const MfaVerifySmsForm = ({mfaProps, application, onFinish, method, user}
|
||||
<Form
|
||||
form={form}
|
||||
style={{width: "300px"}}
|
||||
onFinish={handleFinish}
|
||||
onFinish={onFinish}
|
||||
initialValues={{
|
||||
countryCode: mfaProps.countryCode,
|
||||
enableMfaRemember: false,
|
||||
|
@@ -8,13 +8,6 @@ import * as Setting from "../../Setting";
|
||||
export const MfaVerifyTotpForm = ({mfaProps, onFinish}) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values) => {
|
||||
onFinish({
|
||||
passcode: values.passcode,
|
||||
enableMfaRemember: values.enableMfaRemember,
|
||||
});
|
||||
};
|
||||
|
||||
const renderSecret = () => {
|
||||
if (!mfaProps.secret) {
|
||||
return null;
|
||||
@@ -47,7 +40,7 @@ export const MfaVerifyTotpForm = ({mfaProps, onFinish}) => {
|
||||
<Form
|
||||
form={form}
|
||||
style={{width: "300px"}}
|
||||
onFinish={handleFinish}
|
||||
onFinish={onFinish}
|
||||
initialValues={{
|
||||
enableMfaRemember: false,
|
||||
}}
|
||||
|
@@ -89,3 +89,14 @@ export function verifyInvitation(owner, name) {
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function sendInvitation(invitation, destinations) {
|
||||
return fetch(`${Setting.ServerUrl}/api/send-invitation?id=${invitation.owner}/${encodeURIComponent(invitation.name)}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(destinations),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
@@ -19,13 +19,21 @@ import GridCards from "./GridCards";
|
||||
const AppListPage = (props) => {
|
||||
const [applications, setApplications] = React.useState(null);
|
||||
|
||||
const sort = (applications) => {
|
||||
applications.sort((a, b) => {
|
||||
return a.order - b.order;
|
||||
});
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (props.account === null) {
|
||||
return;
|
||||
}
|
||||
ApplicationBackend.getApplicationsByOrganization("admin", props.account.owner)
|
||||
.then((res) => {
|
||||
setApplications(res.data || []);
|
||||
const applications = res.data || [];
|
||||
sort(applications);
|
||||
setApplications(applications);
|
||||
});
|
||||
}, [props.account]);
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import {ArrowUpOutlined} from "@ant-design/icons";
|
||||
import {Card, Col, Row, Statistic, Tour} from "antd";
|
||||
import {Card, Col, Row, Spin, Statistic, Tour} from "antd";
|
||||
import * as echarts from "echarts";
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
@@ -74,6 +74,8 @@ const Dashboard = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
setDashboardData(null);
|
||||
|
||||
const organization = getOrganizationName();
|
||||
DashboardBackend.getDashboard(organization).then((res) => {
|
||||
if (res.status === "ok") {
|
||||
@@ -110,11 +112,22 @@ const Dashboard = (props) => {
|
||||
};
|
||||
|
||||
const renderEChart = () => {
|
||||
const chartDom = document.getElementById("echarts-chart");
|
||||
|
||||
if (dashboardData === null) {
|
||||
return;
|
||||
if (chartDom) {
|
||||
const instance = echarts.getInstanceByDom(chartDom);
|
||||
if (instance) {
|
||||
instance.dispose();
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||
<Spin size="large" tip={i18next.t("login:Loading")} style={{paddingTop: "10%"}} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const chartDom = document.getElementById("echarts-chart");
|
||||
const myChart = echarts.init(chartDom);
|
||||
const currentDate = new Date();
|
||||
const dateArray = [];
|
||||
|
@@ -20,7 +20,7 @@ import {CaptchaWidget} from "../CaptchaWidget";
|
||||
import {SafetyOutlined} from "@ant-design/icons";
|
||||
|
||||
export const CaptchaModal = (props) => {
|
||||
const {owner, name, visible, onOk, onUpdateToken, onCancel, isCurrentProvider, noModal} = props;
|
||||
const {owner, name, visible, onOk, onUpdateToken, onCancel, isCurrentProvider, noModal, innerRef} = props;
|
||||
|
||||
const [captchaType, setCaptchaType] = React.useState("none");
|
||||
const [clientId, setClientId] = React.useState("");
|
||||
@@ -59,6 +59,14 @@ export const CaptchaModal = (props) => {
|
||||
onCancel?.();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (innerRef) {
|
||||
innerRef.current = {
|
||||
loadCaptcha: loadCaptcha,
|
||||
};
|
||||
}
|
||||
}, [innerRef]);
|
||||
|
||||
const loadCaptcha = () => {
|
||||
UserBackend.getCaptcha(owner, name, isCurrentProvider).then((res) => {
|
||||
if (res.type === "none") {
|
||||
@@ -83,7 +91,7 @@ export const CaptchaModal = (props) => {
|
||||
const renderDefaultCaptcha = () => {
|
||||
if (noModal) {
|
||||
return (
|
||||
<Row style={{textAlign: "center"}}>
|
||||
<Row style={{textAlign: "center"}} gutter={10}>
|
||||
<Col
|
||||
style={{flex: noModal ? "70%" : "100%"}}>
|
||||
<Input
|
||||
|
@@ -133,6 +133,9 @@ function initLanguage() {
|
||||
case "sk-SK":
|
||||
language = "sk";
|
||||
break;
|
||||
case "az":
|
||||
language = "az";
|
||||
break;
|
||||
default:
|
||||
language = Conf.DefaultLanguage;
|
||||
}
|
||||
|
@@ -40,6 +40,8 @@
|
||||
"Custom CSS Mobile": "CSS مخصص للجوال",
|
||||
"Custom CSS Mobile - Edit": "تعديل CSS مخصص للجوال",
|
||||
"Custom CSS Mobile - Tooltip": "CSS مخصص للجوال - تلميح",
|
||||
"Disable signin": "Disable signin",
|
||||
"Disable signin - Tooltip": "Disable signin - Tooltip",
|
||||
"Dynamic": "ديناميكي",
|
||||
"Edit Application": "تحرير التطبيق",
|
||||
"Enable Email linking": "تمكين ربط البريد الإلكتروني",
|
||||
@@ -90,6 +92,8 @@
|
||||
"No verification": "لا توجد مصادقة",
|
||||
"Normal": "عادي",
|
||||
"Only signup": "التسجيل فقط",
|
||||
"Order": "Order",
|
||||
"Order - Tooltip": "Order - Tooltip",
|
||||
"Org choice mode": "وضع اختيار المنظمة",
|
||||
"Org choice mode - Tooltip": "وضع اختيار المنظمة - تلميح",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "يرجى تشغيل \\\"جلسة الدخول\\\" أولاً قبل تشغيل \\\"الدخول التلقائي\\\"",
|
||||
@@ -256,6 +260,7 @@
|
||||
"Close": "إغلاق",
|
||||
"Confirm": "تأكيد",
|
||||
"Copied to clipboard successfully": "تم النسخ إلى الحافظة بنجاح",
|
||||
"Copy": "Copy",
|
||||
"Created time": "وقت الإنشاء",
|
||||
"Custom": "مخصص",
|
||||
"Dashboard": "لوحة التحكم",
|
||||
@@ -290,6 +295,7 @@
|
||||
"Enforcers": "المنفذون",
|
||||
"Failed to add": "فشل الإضافة",
|
||||
"Failed to connect to server": "فشل الاتصال بالخادم",
|
||||
"Failed to copy": "Failed to copy",
|
||||
"Failed to delete": "فشل الحذف",
|
||||
"Failed to enable": "فشل التمكين",
|
||||
"Failed to get TermsOfUse URL": "فشل الحصول على رابط شروط الاستخدام",
|
||||
@@ -301,6 +307,7 @@
|
||||
"Favicon": "الرمز المفضل",
|
||||
"Favicon - Tooltip": "رابط رمز الموقع المستخدم في جميع صفحات Casdoor الخاصة بالمنظمة",
|
||||
"First name": "الاسم الأول",
|
||||
"First name - Tooltip": "The first name of user",
|
||||
"Forced redirect origin - Tooltip": "إعادة توجيه الأصل بالقوة - تلميح",
|
||||
"Forget URL": "رابط نسيان كلمة المرور",
|
||||
"Forget URL - Tooltip": "رابط مخصص لصفحة \"نسيان كلمة المرور\". إذا لم يتم تعيينه، ستُستخدم صفحة Casdoor الافتراضية. عند التعيين، ستُعيد توجيه روابط \"نسيان كلمة المرور\" إلى هذا الرابط",
|
||||
@@ -327,8 +334,10 @@
|
||||
"Languages": "اللغات",
|
||||
"Languages - Tooltip": "اللغات المتاحة",
|
||||
"Last name": "الاسم الأخير",
|
||||
"Last name - Tooltip": "The last name of user",
|
||||
"Later": "لاحقًا",
|
||||
"Logging & Auditing": "التسجيل والمراجعة",
|
||||
"Login page": "Login page",
|
||||
"Logo": "الشعار",
|
||||
"Logo - Tooltip": "الأيقونات التي يعرضها التطبيق للعالم الخارجي",
|
||||
"Logo dark": "الشعار المظلم",
|
||||
@@ -410,6 +419,7 @@
|
||||
"SSH type - Tooltip": "نوع المصادقة لاتصال SSH",
|
||||
"Save": "حفظ",
|
||||
"Save & Exit": "حفظ وخروج",
|
||||
"Send": "Send",
|
||||
"Session ID": "معرف الجلسة",
|
||||
"Sessions": "الجلسات",
|
||||
"Shortcuts": "الاختصارات",
|
||||
@@ -427,6 +437,7 @@
|
||||
"State - Tooltip": "الحالة - تلميح",
|
||||
"Subscriptions": "الاشتراكات",
|
||||
"Successfully added": "تمت الإضافة بنجاح",
|
||||
"Successfully copied": "Successfully copied",
|
||||
"Successfully deleted": "تم الحذف بنجاح",
|
||||
"Successfully removed": "تمت الإزالة بنجاح",
|
||||
"Successfully saved": "تم الحفظ بنجاح",
|
||||
@@ -441,6 +452,7 @@
|
||||
"Sync": "مزامنة",
|
||||
"Syncers": "المزامنات",
|
||||
"System Info": "معلومات النظام",
|
||||
"Tab": "Tab",
|
||||
"There was a problem signing you in..": "حدثت مشكلة أثناء تسجيل دخولك..",
|
||||
"This is a read-only demo site!": "هذا موقع تجريبي للقراءة فقط!",
|
||||
"Timestamp": "الطابع الزمني",
|
||||
@@ -573,6 +585,7 @@
|
||||
"Please type an organization to sign in": "يرجى كتابة منظمة لتسجيل الدخول",
|
||||
"Redirecting, please wait.": "جار إعادة التوجيه، يرجى الانتظار.",
|
||||
"Refresh": "تحديث",
|
||||
"Select organization": "Select organization",
|
||||
"Sign In": "تسجيل الدخول",
|
||||
"Sign in with Face ID": "تسجيل الدخول باستخدام معرف الوجه",
|
||||
"Sign in with WebAuthn": "تسجيل الدخول باستخدام WebAuthn",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user