Compare commits

...

19 Commits

Author SHA1 Message Date
267833d9f9 feat: fix the application edit page bug due to this.props.location.search (#1055) 2022-08-22 15:13:58 +08:00
2d3d1167bb Fix HasPromptPage() for signup items 2022-08-22 11:51:20 +08:00
ef5abdfa8f feat: rollback to fix ci (#1051) 2022-08-22 11:14:51 +08:00
580d43101e fix(i18n): add spanish translations (#1043)
* feat(i18n): add spanish translations

* feat(i18n): add missing translations

* feat(i18n): use new icon flag set

* use document protocol

* fix(i18n): use our static flags
2022-08-22 09:42:28 +08:00
fdf2b880cb feat: click on the app card to log in automatically (#1049) 2022-08-22 01:17:18 +08:00
80a2263b18 fix: fix ci bug: "/go/src/casdoor/.git/refs/heads" not found (#1050) 2022-08-22 01:02:57 +08:00
1f11d22c1c fix: add managed account table for supporting Chrome extension to auto login (#1030)
* feat: add manage accounts table(support chrome extension to auto login)

* fix go lint err

* rename manageAccounts to managedAccounts

* expand up&down buttom column width

* rename ManagedAccountsTable to ManagedAccountTable
2022-08-22 00:25:39 +08:00
b6988286b5 Improve i18n for permission page 2022-08-21 23:17:14 +08:00
64f787fab5 feat: can modify static resource url by app.conf (#1045)
* feat: can modify static resource url by app.conf

Signed-off-by: magicwind <2814461814@qq.com>

* Update static_filter.go

Signed-off-by: magicwind <2814461814@qq.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-21 21:40:27 +08:00
39c6bd5850 fix: country/region prompted page not show when signin (#1047) 2022-08-21 17:41:07 +08:00
7312c5ce3c Don't check domain for submitPermissionEdit() 2022-08-21 15:28:19 +08:00
0bc5b90218 fix: add country/region selectbox in prompt page (#1022) 2022-08-21 11:12:23 +08:00
f3b3376a3c fix: fix get version error (#1044)
* feat: fix get version error

* feat: more safe

* fix
2022-08-21 10:47:36 +08:00
feec6abd88 fix: fix translations for system info page (#1042) 2022-08-20 23:00:37 +08:00
c50042c85a feat: fix the go.sum error (#1040) 2022-08-20 22:04:37 +08:00
ef4c3833a4 feat: add system info page (#1033)
* feat: add system info page

* feat: add some code

* fix
2022-08-20 21:22:46 +08:00
67a5adf585 feat: replace panic with details json error payload. (#1039)
Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2022-08-20 21:09:32 +08:00
08a1e7ae32 fix: keep phone/email unique. (#1038)
Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2022-08-20 12:14:08 +08:00
7d979cbaf0 feat(storage): add support for min.io storage (#1037)
* feat(storage): add support for min.io storage

* fix(minio): use doublequote

* fix(storage): change storage name to MinIO
2022-08-20 11:30:13 +08:00
65 changed files with 1858 additions and 143 deletions

View File

@ -107,6 +107,7 @@ p, *, *, POST, /api/acs, *, *
p, *, *, GET, /api/saml/metadata, *, *
p, *, *, *, /cas, *, *
p, *, *, *, /api/webauthn, *, *
p, *, *, GET, /api/get-release, *, *
`
sa := stringadapter.NewAdapter(ruleText)

View File

@ -105,7 +105,8 @@ func (c *ApiController) Signup() {
var form RequestForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
@ -156,6 +157,12 @@ func (c *ApiController) Signup() {
username = id
}
initScore, err := getInitScore()
if err != nil {
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
return
}
user := &object.User{
Owner: form.Organization,
Name: username,
@ -171,7 +178,7 @@ func (c *ApiController) Signup() {
Affiliation: form.Affiliation,
IdCard: form.IdCard,
Region: form.Region,
Score: getInitScore(),
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,

View File

@ -111,8 +111,7 @@ func (c *ApiController) GetOrganizationApplications() {
return
}
var applications []*object.Application
applications = object.GetApplicationsByOrganizationName(owner, organization)
applications := object.GetApplicationsByOrganizationName(owner, organization)
c.Data["json"] = object.GetMaskedApplications(applications, userId)
c.ServeJSON()
}
@ -131,7 +130,8 @@ func (c *ApiController) UpdateApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
@ -149,7 +149,8 @@ func (c *ApiController) AddApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
@ -167,7 +168,8 @@ func (c *ApiController) DeleteApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteApplication(&application))

View File

@ -344,7 +344,7 @@ func (c *ApiController) Login() {
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
}
if user != nil && user.IsDeleted == false {
if user != nil && !user.IsDeleted {
// Sign in via OAuth (want to sign up but already have account)
if user.IsForbidden {
@ -384,6 +384,12 @@ func (c *ApiController) Login() {
properties := map[string]string{}
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
initScore, err := getInitScore()
if err != nil {
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
return
}
user = &object.User{
Owner: application.Organization,
Name: userInfo.Username,
@ -394,7 +400,7 @@ func (c *ApiController) Login() {
Avatar: userInfo.AvatarUrl,
Address: []string{},
Email: userInfo.Email,
Score: getInitScore(),
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,

View File

@ -19,6 +19,7 @@ import (
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -58,6 +59,7 @@ func (c *ApiController) IsGlobalAdmin() bool {
func (c *ApiController) GetSessionUsername() string {
// check if user session expired
sessionData := c.GetSessionData()
if sessionData != nil &&
sessionData.ExpireTime != 0 &&
sessionData.ExpireTime < time.Now().Unix() {
@ -120,7 +122,8 @@ func (c *ApiController) GetSessionData() *SessionData {
sessionData := &SessionData{}
err := util.JsonToStruct(session.(string), sessionData)
if err != nil {
panic(err)
logs.Error("GetSessionData failed, error: %s", err)
return nil
}
return sessionData

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert))
@ -94,7 +95,8 @@ func (c *ApiController) AddCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddCert(&cert))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert))

View File

@ -30,7 +30,8 @@ func (c *ApiController) Enforce() {
var permissionRule object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.Enforce(userId, &permissionRule)
@ -47,7 +48,8 @@ func (c *ApiController) BatchEnforce() {
var permissionRules []object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.BatchEnforce(userId, permissionRules)

View File

@ -199,7 +199,8 @@ func (c *ApiController) DeleteLdap() {
var ldap object.Ldap
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id)
@ -217,7 +218,8 @@ func (c *ApiController) SyncLdapUsers() {
var users []object.LdapRespUser
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
object.UpdateLdapSyncTime(ldapId)
@ -239,7 +241,8 @@ func (c *ApiController) CheckLdapUsersExist() {
var uuids []string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &uuids)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
exist := object.CheckLdapUuidExist(owner, uuids)

View File

@ -37,7 +37,8 @@ func (c *ApiController) Unlink() {
var form LinkForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
providerType := form.ProviderType

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateModel(id, &model))
@ -94,7 +95,8 @@ func (c *ApiController) AddModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddModel(&model))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteModel(&model))

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
@ -94,7 +95,8 @@ func (c *ApiController) AddOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteOrganization(&organization))

View File

@ -95,7 +95,8 @@ func (c *ApiController) UpdatePayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdatePayment(id, &payment))
@ -113,7 +114,8 @@ func (c *ApiController) AddPayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddPayment(&payment))
@ -131,7 +133,8 @@ func (c *ApiController) DeletePayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeletePayment(&payment))
@ -157,7 +160,8 @@ func (c *ApiController) NotifyPayment() {
if ok {
_, err := c.Ctx.ResponseWriter.Write([]byte("success"))
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
} else {
panic(fmt.Errorf("NotifyPayment() failed: %v", ok))

View File

@ -94,7 +94,8 @@ func (c *ApiController) UpdatePermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission))
@ -112,7 +113,8 @@ func (c *ApiController) AddPermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddPermission(&permission))
@ -130,7 +132,8 @@ func (c *ApiController) DeletePermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission))

View File

@ -80,7 +80,8 @@ func (c *ApiController) UpdateProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProduct(id, &product))
@ -98,7 +99,8 @@ func (c *ApiController) AddProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddProduct(&product))
@ -116,7 +118,8 @@ func (c *ApiController) DeleteProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
@ -94,7 +95,8 @@ func (c *ApiController) AddProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))

View File

@ -59,7 +59,8 @@ func (c *ApiController) GetRecordsByFilter() {
record := &object.Record{}
err := util.JsonToStruct(body, record)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.GetRecordsByField(record)

View File

@ -72,7 +72,8 @@ func (c *ApiController) UpdateResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateResource(id, &resource))
@ -87,7 +88,8 @@ func (c *ApiController) AddResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddResource(&resource))
@ -102,7 +104,8 @@ func (c *ApiController) DeleteResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
provider, _, ok := c.GetProviderFromContext("Storage")

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateRole(id, &role))
@ -94,7 +95,8 @@ func (c *ApiController) AddRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddRole(&role))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteRole(&role))

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
@ -94,7 +95,8 @@ func (c *ApiController) AddSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddSyncer(&syncer))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSyncer(&syncer))

View File

@ -0,0 +1,82 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
type SystemInfo struct {
MemoryUsed uint64 `json:"memory_used"`
MemoryTotal uint64 `json:"memory_total"`
CpuUsage []float64 `json:"cpu_usage"`
}
// GetSystemInfo
// @Title GetSystemInfo
// @Tag System API
// @Description get user's system info
// @Param id query string true "The id of the user"
// @Success 200 {object} object.SystemInfo The Response object
// @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() {
id := c.GetString("id")
if id == "" {
id = c.GetSessionUsername()
}
user := object.GetUser(id)
if user == nil || !user.IsGlobalAdmin {
c.ResponseError("You are not authorized to access this resource")
return
}
cpuUsage, err := util.GetCpuUsage()
if err != nil {
c.ResponseError(err.Error())
return
}
memoryUsed, memoryTotal, err := util.GetMemoryUsage()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = SystemInfo{
CpuUsage: cpuUsage,
MemoryUsed: memoryUsed,
MemoryTotal: memoryTotal,
}
c.ServeJSON()
}
// GitRepoVersion
// @Title GitRepoVersion
// @Tag System API
// @Description get local github repo's latest release version info
// @Success 200 {string} local latest version hash of casdoor
// @router /get-release [get]
func (c *ApiController) GitRepoVersion() {
version, err := util.GetGitRepoVersion()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = version
c.ServeJSON()
}

View File

@ -79,7 +79,8 @@ func (c *ApiController) UpdateToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
@ -97,7 +98,8 @@ func (c *ApiController) AddToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddToken(&token))
@ -115,7 +117,8 @@ func (c *ApiController) DeleteToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteToken(&token))

View File

@ -149,7 +149,8 @@ func (c *ApiController) UpdateUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
if user.DisplayName == "" {
@ -183,7 +184,8 @@ func (c *ApiController) AddUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
@ -201,7 +203,8 @@ func (c *ApiController) DeleteUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
@ -220,7 +223,8 @@ func (c *ApiController) GetEmailAndPhone() {
var form RequestForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
user := object.GetUserByFields(form.Organization, form.Username)
@ -306,7 +310,8 @@ func (c *ApiController) CheckUserPassword() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
_, msg := object.CheckUserPassword(user.Owner, user.Name, user.Password)

View File

@ -24,17 +24,18 @@ import (
"github.com/casdoor/casdoor/util"
)
func saveFile(path string, file *multipart.File) {
func saveFile(path string, file *multipart.File) (err error) {
f, err := os.Create(path)
if err != nil {
panic(err)
return err
}
defer f.Close()
_, err = io.Copy(f, *file)
if err != nil {
panic(err)
return err
}
return nil
}
func (c *ApiController) UploadUsers() {
@ -43,13 +44,18 @@ func (c *ApiController) UploadUsers() {
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
path := util.GetUploadXlsxPath(fileId)
util.EnsureFileFolderExists(path)
saveFile(path, &file)
err = saveFile(path, &file)
if err != nil {
c.ResponseError(err.Error())
return
}
affected := object.UploadUsers(owner, fileId)
if affected {

View File

@ -23,9 +23,8 @@ import (
"github.com/casdoor/casdoor/util"
)
// ResponseOk ...
func (c *ApiController) ResponseOk(data ...interface{}) {
resp := Response{Status: "ok"}
// ResponseJsonData ...
func (c *ApiController) ResponseJsonData(resp *Response, data ...interface{}) {
switch len(data) {
case 2:
resp.Data2 = data[1]
@ -37,18 +36,16 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
c.ServeJSON()
}
// ResponseOk ...
func (c *ApiController) ResponseOk(data ...interface{}) {
resp := &Response{Status: "ok"}
c.ResponseJsonData(resp, data...)
}
// ResponseError ...
func (c *ApiController) ResponseError(error string, data ...interface{}) {
resp := Response{Status: "error", Msg: error}
switch len(data) {
case 2:
resp.Data2 = data[1]
fallthrough
case 1:
resp.Data = data[0]
}
c.Data["json"] = resp
c.ServeJSON()
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
}
// SetTokenErrorHttpStatus ...
@ -78,13 +75,8 @@ func (c *ApiController) RequireSignedIn() (string, bool) {
return userId, true
}
func getInitScore() int {
score, err := strconv.Atoi(conf.GetConfigString("initScore"))
if err != nil {
panic(err)
}
return score
func getInitScore() (int, error) {
return strconv.Atoi(conf.GetConfigString("initScore"))
}
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {

View File

@ -76,7 +76,8 @@ func (c *ApiController) UpdateWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
@ -94,7 +95,8 @@ func (c *ApiController) AddWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddWebhook(&webhook))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteWebhook(&webhook))

7
go.mod
View File

@ -21,6 +21,7 @@ require (
github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/uuid v1.2.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v0.9.0
@ -31,13 +32,17 @@ require (
github.com/russellhaering/gosaml2 v0.6.0
github.com/russellhaering/goxmldsig v1.1.1
github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.8.0
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/ini.v1 v1.62.0 // indirect

28
go.sum
View File

@ -156,6 +156,8 @@ github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -219,8 +221,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -376,6 +379,8 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
@ -389,13 +394,15 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@ -406,6 +413,10 @@ github.com/tencentcloud/tencentcloud-sdk-go v1.0.154 h1:THBgwGwUQtsw6L53cSSA2wwL
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
@ -417,6 +428,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@ -537,6 +550,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -563,8 +577,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -626,7 +642,6 @@ golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4X
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -739,8 +754,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -45,7 +45,8 @@ func main() {
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
// beego.DelStaticPath("/static")
beego.SetStaticPath("/static", "web/build/static")
// beego.SetStaticPath("/static", "web/build/static")
beego.BConfig.WebConfig.DirectoryIndex = true
beego.SetStaticPath("/swagger", "swagger")
beego.SetStaticPath("/files", "files")

View File

@ -73,6 +73,10 @@ func (application *Application) IsSignupItemRequired(itemName string) bool {
return signupItem.Required
}
func (si *SignupItem) isSignupItemPrompted() bool {
return si.Visible && si.Prompted
}
func (application *Application) GetSignupItemRule(itemName string) string {
signupItem := application.getSignupItem(itemName)
if signupItem == nil {
@ -92,6 +96,16 @@ func (application *Application) getAllPromptedProviderItems() []*ProviderItem {
return res
}
func (application *Application) getAllPromptedSignupItems() []*SignupItem {
res := []*SignupItem{}
for _, signupItem := range application.SignupItems {
if signupItem.isSignupItemPrompted() {
res = append(res, signupItem)
}
}
return res
}
func (application *Application) isAffiliationPrompted() bool {
signupItem := application.getSignupItem("Affiliation")
if signupItem == nil {
@ -107,5 +121,10 @@ func (application *Application) HasPromptPage() bool {
return true
}
signupItems := application.getAllPromptedSignupItems()
if len(signupItems) != 0 {
return true
}
return application.isAffiliationPrompted()
}

View File

@ -62,10 +62,10 @@ func CheckUserSignup(application *Application, organization *Organization, usern
if HasUserByField(organization.Name, "name", username) {
return "username already exists"
}
if HasUserByField(organization.Name, "email", username) {
if HasUserByField(organization.Name, "email", email) {
return "email already exists"
}
if HasUserByField(organization.Name, "phone", username) {
if HasUserByField(organization.Name, "phone", phone) {
return "phone already exists"
}
}

View File

@ -84,6 +84,7 @@ func initBuiltInOrganization() bool {
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
},
}
AddOrganization(organization)

View File

@ -46,7 +46,7 @@ type Organization struct {
EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
AccountItems []*AccountItem `xorm:"varchar(2000)" json:"accountItems"`
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
}
func GetOrganizationCount(owner, field, value string) int {

View File

@ -114,6 +114,8 @@ type User struct {
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
SigninWrongTimes int `json:"signinWrongTimes"`
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
}
type Userinfo struct {
@ -128,6 +130,13 @@ type Userinfo struct {
Phone string `json:"phone,omitempty"`
}
type ManagedAccount struct {
Application string `xorm:"varchar(100)" json:"application"`
Username string `xorm:"varchar(100)" json:"username"`
Password string `xorm:"varchar(100)" json:"password"`
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
}
func GetGlobalUserCount(field, value string) int {
session := GetSession("", -1, -1, field, value, "", "")
count, err := session.Count(&User{})
@ -334,6 +343,12 @@ func GetMaskedUser(user *User) *User {
if user.Password != "" {
user.Password = "***"
}
if user.ManagedAccounts != nil {
for _, manageAccount := range user.ManagedAccounts {
manageAccount.Password = "***"
}
}
return user
}
@ -378,7 +393,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
columns = []string{
"owner", "display_name", "avatar",
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials",
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"signin_wrong_times", "last_signin_wrong_time",
}
}

View File

@ -202,4 +202,7 @@ func initAPI() {
beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish")
beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin")
beego.Router("/api/webauthn/signin/finish", &controllers.ApiController{}, "Post:WebAuthnSigninFinish")
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
beego.Router("/api/get-release", &controllers.ApiController{}, "GET:GitRepoVersion")
}

View File

@ -16,12 +16,19 @@ package routers
import (
"net/http"
"os"
"strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/casdoor/casdoor/util"
)
var (
oldStaticBaseUrl = "https://cdn.casbin.org"
newStaticBaseUrl = beego.AppConfig.String("staticBaseUrl")
)
func StaticFilter(ctx *context.Context) {
urlPath := ctx.Request.URL.Path
if strings.HasPrefix(urlPath, "/api/") || strings.HasPrefix(urlPath, "/.well-known/") {
@ -38,9 +45,35 @@ func StaticFilter(ctx *context.Context) {
path += urlPath
}
if util.FileExist(path) {
if !util.FileExist(path) {
path = "web/build/index.html"
}
if oldStaticBaseUrl == newStaticBaseUrl {
http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
} else {
http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path, oldStaticBaseUrl, newStaticBaseUrl)
}
}
func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, old string, new string) {
f, err := os.Open(name)
if err != nil {
panic(err)
}
defer f.Close()
d, err := f.Stat()
if err != nil {
panic(err)
}
oldContent := util.ReadStringFromPath(name)
newContent := strings.ReplaceAll(oldContent, old, new)
http.ServeContent(w, r, d.Name(), d.ModTime(), strings.NewReader(newContent))
_, err = w.Write([]byte(newContent))
if err != nil {
panic(err)
}
}

36
storage/minio_s3.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package storage
import (
awss3 "github.com/aws/aws-sdk-go/service/s3"
"github.com/casdoor/oss"
"github.com/casdoor/oss/s3"
)
func NewMinIOS3StorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
sp := s3.New(&s3.Config{
AccessID: clientId,
AccessKey: clientSecret,
Region: region,
Bucket: bucket,
Endpoint: endpoint,
S3Endpoint: endpoint,
ACL: awss3.BucketCannedACLPublicRead,
S3ForcePathStyle: true,
})
return sp
}

View File

@ -22,6 +22,8 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
return NewLocalFileSystemStorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "AWS S3":
return NewAwsS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "MinIO":
return NewMinIOS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "Aliyun OSS":
return NewAliyunOssStorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "Tencent Cloud COS":

78
util/system.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"io/ioutil"
"os"
"runtime"
"strings"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/mem"
)
// get cpu usage
func GetCpuUsage() ([]float64, error) {
usage, err := cpu.Percent(time.Second, true)
return usage, err
}
var fileDate, version string
// get memory usage
func GetMemoryUsage() (uint64, uint64, error) {
virtualMem, err := mem.VirtualMemory()
if err != nil {
return 0, 0, err
}
var m runtime.MemStats
runtime.ReadMemStats(&m)
return m.TotalAlloc, virtualMem.Total, nil
}
// get github repo release version
func GetGitRepoVersion() (string, error) {
pwd, err := os.Getwd()
if err != nil {
return "", err
}
fileInfos, err := ioutil.ReadDir(pwd + "/.git/refs/heads")
for _, v := range fileInfos {
if v.Name() == "master" {
if v.ModTime().String() == fileDate {
return version, nil
} else {
fileDate = v.ModTime().String()
break
}
}
}
content, err := ioutil.ReadFile(pwd + "/.git/refs/heads/master")
if err != nil {
return "", err
}
// Convert to full length
temp := string(content)
version = strings.ReplaceAll(temp, "\n", "")
return version, nil
}

33
util/sysytem_test.go Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetCpuUsage(t *testing.T) {
usage, err := GetCpuUsage()
assert.Nil(t, err)
t.Log(usage)
}
func TestGetMemoryUsage(t *testing.T) {
used, total, err := GetMemoryUsage()
assert.Nil(t, err)
t.Log(used, total)
}

View File

@ -19,7 +19,7 @@
name="description"
content="Casdoor - An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS"
/>
<link rel="apple-touch-icon" href="https://cdn.casdoor.com/static/favicon.png" />
<link rel="apple-touch-icon" href="https://cdn.casbin.org/img/favicon.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/

View File

@ -95,6 +95,7 @@ class AccountTable extends React.Component {
{name: "Is forbidden", displayName: i18next.t("user:Is forbidden")},
{name: "Is deleted", displayName: i18next.t("user:Is deleted")},
{name: "WebAuthn credentials", displayName: i18next.t("user:WebAuthn credentials")},
{name: "Managed accounts", displayName: i18next.t("user:Managed accounts")},
];
const getItemDisplayName = (text) => {

View File

@ -71,6 +71,7 @@ import SamlCallback from "./auth/SamlCallback";
import CasLogout from "./auth/CasLogout";
import ModelListPage from "./ModelListPage";
import ModelEditPage from "./ModelEditPage";
import SystemInfo from "./SystemInfo";
const {Header, Footer} = Layout;
@ -148,6 +149,8 @@ class App extends Component {
this.setState({selectedMenuKey: "/login"});
} else if (uri.includes("/result")) {
this.setState({selectedMenuKey: "/result"});
} else if (uri.includes("/sysinfo")) {
this.setState({selectedMenuKey: "/sysinfo"});
} else {
this.setState({selectedMenuKey: -1});
}
@ -478,8 +481,14 @@ class App extends Component {
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/sysinfo">
<Link to="/sysinfo">
{i18next.t("general:SysInfo")}
</Link>
</Menu.Item>
);
}
res.push(
<Menu.Item key="/swagger">
<a target="_blank" rel="noreferrer" href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>
@ -560,6 +569,7 @@ class App extends Component {
<Route exact path="/payments/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
</Switch>
@ -691,6 +701,7 @@ class App extends Component {
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...props} />)} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage account={this.state.account} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage account={this.state.account} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} {...props} />)} />
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo {...props} />)} />
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
</Switch>

View File

@ -0,0 +1,165 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Select, Table, Tooltip} from "antd";
import * as Setting from "./Setting";
import i18next from "i18next";
const {Option} = Select;
class ManagedAccountTable extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
};
}
updateTable(table) {
this.props.onUpdateTable(table);
}
updateField(table, index, key, value) {
table[index][key] = value;
this.updateTable(table);
}
addRow(table) {
const row = {application: "", username: "", password: "", signinUrl: ""};
if (table === undefined || table === null) {
table = [];
}
table = Setting.addRow(table, row);
this.updateTable(table);
}
deleteRow(table, i) {
table = Setting.deleteRow(table, i);
this.updateTable(table);
}
upRow(table, i) {
table = Setting.swapRow(table, i - 1, i);
this.updateTable(table);
}
downRow(table, i) {
table = Setting.swapRow(table, i, i + 1);
this.updateTable(table);
}
renderTable(table) {
const columns = [
{
title: i18next.t("general:Application"),
dataIndex: "application",
key: "application",
render: (text, record, index) => {
const items = this.props.applications;
const signinUrlMap = new Map();
for (const application of items) {
signinUrlMap.set(application.name, application.signinUrl);
}
return (
<Select virtual={false} style={{width: "100%"}}
value={text}
onChange={value => {
this.updateField(table, index, "application", value);
this.updateField(table, index, "signinUrl", signinUrlMap.get(value));
}} >
{
items.map((item, index) => <Option key={index} value={item.name}>{item.name}</Option>)
}
</Select>
);
},
},
{
title: i18next.t("signup:Username"),
dataIndex: "username",
key: "username",
width: "420px",
render: (text, record, index) => {
return (
<Input defaultValue={text} onChange={e => {
this.updateField(table, index, "username", e.target.value);
}} />
);
},
},
{
title: i18next.t("general:Password"),
dataIndex: "password",
key: "password",
width: "420px",
render: (text, record, index) => {
return (
<Input defaultValue={text} onChange={e => {
this.updateField(table, index, "password", e.target.value);
}} />
);
},
},
{
title: i18next.t("general:Action"),
key: "action",
width: "100px",
render: (text, record, index) => {
return (
<div>
<Tooltip placement="bottomLeft" title={i18next.t("general:Up")}>
<Button style={{marginRight: "5px"}} disabled={index === 0} icon={<UpOutlined />} size="small" onClick={() => this.upRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={i18next.t("general:Down")}>
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
</Tooltip>
</div>
);
},
},
];
return (
<Table scroll={{x: "max-content"}} rowKey="name" columns={columns} dataSource={table} size="middle" bordered pagination={false}
title={() => (
<div>
{this.props.title}&nbsp;&nbsp;&nbsp;&nbsp;
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
</div>
)}
/>
);
}
render() {
return (
<div>
<Row style={{marginTop: "20px"}} >
<Col span={24}>
{
this.renderTable(this.props.table)
}
</Col>
</Row>
</div>
);
}
}
export default ManagedAccountTable;

View File

@ -245,7 +245,8 @@ class PermissionEditPage extends React.Component {
})}>
{
[
{id: "Application", name: "Application"},
{id: "Application", name: i18next.t("general:Application")},
{id: "TreeNode", name: i18next.t("permission:TreeNode")},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
@ -273,9 +274,9 @@ class PermissionEditPage extends React.Component {
})}>
{
[
{id: "Read", name: "Read"},
{id: "Write", name: "Write"},
{id: "Admin", name: "Admin"},
{id: "Read", name: i18next.t("permission:Read")},
{id: "Write", name: i18next.t("permission:Write")},
{id: "Admin", name: i18next.t("permission:Admin")},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
@ -291,8 +292,8 @@ class PermissionEditPage extends React.Component {
})}>
{
[
{id: "Allow", name: "Allow"},
{id: "Deny", name: "Deny"},
{id: "Allow", name: i18next.t("permission:Allow")},
{id: "Deny", name: i18next.t("permission:Deny")},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
@ -358,8 +359,8 @@ class PermissionEditPage extends React.Component {
})}>
{
[
{id: "Approved", name: "Approved"},
{id: "Pending", name: "Pending"},
{id: "Approved", name: i18next.t("permission:Approved")},
{id: "Pending", name: i18next.t("permission:Pending")},
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
}
</Select>
@ -374,10 +375,10 @@ class PermissionEditPage extends React.Component {
Setting.showMessage("error", "The users and roles cannot be empty at the same time");
return;
}
if (this.state.permission.domains.length === 0) {
Setting.showMessage("error", "The domains cannot be empty");
return;
}
// if (this.state.permission.domains.length === 0) {
// Setting.showMessage("error", "The domains cannot be empty");
// return;
// }
if (this.state.permission.resources.length === 0) {
Setting.showMessage("error", "The resources cannot be empty");
return;

View File

@ -188,7 +188,19 @@ class PermissionListPage extends BaseListPage {
sorter: true,
...this.getColumnSearchProps("actions"),
render: (text, record, index) => {
return Setting.getTags(text);
const tags = text.map((tag, i) => {
switch (tag) {
case "Read":
return i18next.t("permission:Read");
case "Write":
return i18next.t("permission:Write");
case "Admin":
return i18next.t("permission:Admin");
default:
return null;
}
});
return Setting.getTags(tags);
},
},
{
@ -197,11 +209,21 @@ class PermissionListPage extends BaseListPage {
key: "effect",
filterMultiple: false,
filters: [
{text: "Allow", value: "Allow"},
{text: "Deny", value: "Deny"},
{text: i18next.t("permission:Allow"), value: "Allow"},
{text: i18next.t("permission:Deny"), value: "Deny"},
],
width: "120px",
sorter: true,
render: (text, record, index) => {
switch (text) {
case "Allow":
return Setting.getTag("success", i18next.t("permission:Allow"));
case "Deny":
return Setting.getTag("error", i18next.t("permission:Deny"));
default:
return null;
}
},
},
{
title: i18next.t("general:Is enabled"),
@ -248,11 +270,21 @@ class PermissionListPage extends BaseListPage {
key: "state",
filterMultiple: false,
filters: [
{text: "Approved", value: "Approved"},
{text: "Pending", value: "Pending"},
{text: i18next.t("permission:Approved"), value: "Approved"},
{text: i18next.t("permission:Pending"), value: "Pending"},
],
width: "120px",
sorter: true,
render: (text, record, index) => {
switch (text) {
case "Approved":
return Setting.getTag("success", i18next.t("permission:Approved"));
case "Pending":
return Setting.getTag("error", i18next.t("permission:Pending"));
default:
return null;
}
},
},
{
title: i18next.t("general:Action"),

View File

@ -474,7 +474,7 @@ class ProviderEditPage extends React.Component {
}} />
</Col>
</Row>
{this.state.provider.type === "AWS S3" || this.state.provider.type === "Tencent Cloud COS" ? (
{["AWS S3", "MinIO", "Tencent Cloud COS"].includes(this.state.provider.type) ? (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :

View File

@ -15,12 +15,13 @@
import React from "react";
import * as Setting from "./Setting";
import {Dropdown, Menu} from "antd";
import {createFromIconfontCN} from "@ant-design/icons";
import "./App.less";
const IconFont = createFromIconfontCN({
scriptUrl: "//at.alicdn.com/t/font_2680620_ffij16fkwdg.js",
});
function flagIcon(country, alt) {
return (
<img width={24} alt={alt} src={`${Setting.StaticBaseUrl}/flag-icons/${country}.svg`} />
);
}
class SelectLanguageBox extends React.Component {
constructor(props) {
@ -35,13 +36,14 @@ class SelectLanguageBox extends React.Component {
<Menu onClick={(e) => {
Setting.changeLanguage(e.key);
}}>
<Menu.Item key="en" icon={<IconFont type="icon-en" />}>English</Menu.Item>
<Menu.Item key="zh" icon={<IconFont type="icon-zh" />}>简体中文</Menu.Item>
<Menu.Item key="fr" icon={<IconFont type="icon-fr" />}>Français</Menu.Item>
<Menu.Item key="de" icon={<IconFont type="icon-de" />}>Deutsch</Menu.Item>
<Menu.Item key="ja" icon={<IconFont type="icon-ja" />}>日本語</Menu.Item>
<Menu.Item key="ko" icon={<IconFont type="icon-ko" />}>한국어</Menu.Item>
<Menu.Item key="ru" icon={<IconFont type="icon-ru" />}>Русский</Menu.Item>
<Menu.Item key="en" icon={flagIcon("US", "English")}>English</Menu.Item>
<Menu.Item key="es" icon={flagIcon("ES", "Español")}>Español</Menu.Item>
<Menu.Item key="zh" icon={flagIcon("CN", "简体中文")}>简体中文</Menu.Item>
<Menu.Item key="fr" icon={flagIcon("FR", "Français")}>Français</Menu.Item>
<Menu.Item key="de" icon={flagIcon("DE", "Deutsch")}>Deutsch</Menu.Item>
<Menu.Item key="ja" icon={flagIcon("JP", "日本語")}>日本語</Menu.Item>
<Menu.Item key="ko" icon={flagIcon("KR", "한국어")}>한국어</Menu.Item>
<Menu.Item key="ru" icon={flagIcon("RU", "Русский")}>Русский</Menu.Item>
</Menu>
);

View File

@ -69,6 +69,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_aws.png`,
url: "https://aws.amazon.com/s3",
},
"MinIO": {
logo: "https://min.io/resources/img/logo.svg",
url: "https://min.io/",
},
"Aliyun OSS": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
url: "https://aliyun.com/product/oss",
@ -204,10 +208,18 @@ export function isProviderPrompted(providerItem) {
return isProviderVisible(providerItem) && providerItem.prompted;
}
export function isSignupItemPrompted(signupItem) {
return signupItem.visible && signupItem.prompted;
}
export function getAllPromptedProviderItems(application) {
return application.providers.filter(providerItem => isProviderPrompted(providerItem));
}
export function getAllPromptedSignupItems(application) {
return application.signupItems.filter(signupItem => isSignupItemPrompted(signupItem));
}
export function getSignupItem(application, itemName) {
const signupItems = application.signupItems?.filter(signupItem => signupItem.name === itemName);
if (signupItems.length === 0) {
@ -279,6 +291,11 @@ export function hasPromptPage(application) {
return true;
}
const signupItems = getAllPromptedSignupItems(application);
if (signupItems.length !== 0) {
return true;
}
return isAffiliationPrompted(application);
}
@ -303,6 +320,19 @@ function isProviderItemAnswered(user, application, providerItem) {
return linkedValue !== undefined && linkedValue !== "";
}
function isSignupItemAnswered(user, signupItem) {
if (user === null) {
return false;
}
if (signupItem.name !== "Country/Region") {
return true;
}
const value = user["region"];
return value !== undefined && value !== "";
}
export function isPromptAnswered(user, application) {
if (!isAffiliationAnswered(user, application)) {
return false;
@ -314,6 +344,13 @@ export function isPromptAnswered(user, application) {
return false;
}
}
const signupItems = getAllPromptedSignupItems(application);
for (let i = 0; i < signupItems.length; i++) {
if (!isSignupItemAnswered(user, signupItems[i])) {
return false;
}
}
return true;
}
@ -612,6 +649,7 @@ export function getProviderTypeOptions(category) {
[
{id: "Local File System", name: "Local File System"},
{id: "AWS S3", name: "AWS S3"},
{id: "MinIO", name: "MinIO"},
{id: "Aliyun OSS", name: "Aliyun OSS"},
{id: "Tencent Cloud COS", name: "Tencent Cloud COS"},
{id: "Azure Blob", name: "Azure Blob"},
@ -819,7 +857,10 @@ export function getTagColor(s) {
export function getTags(tags) {
const res = [];
if (!tags) {return res;}
if (!tags) {
return res;
}
tags.forEach((tag, i) => {
res.push(
<Tag color={getTagColor(tag)}>
@ -830,6 +871,14 @@ export function getTags(tags) {
return res;
}
export function getTag(color, text) {
return (
<Tag color={color}>
{text}
</Tag>
);
}
export function getApplicationOrgName(application) {
return `${application?.organizationObj.owner}/${application?.organizationObj.name}`;
}

View File

@ -152,7 +152,7 @@ class SignupTable extends React.Component {
return null;
}
if (record.visible) {
if (record.visible && record.name !== "Country/Region") {
return null;
}

127
web/src/SystemInfo.js Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Card, Col, Divider, Progress, Row, Spin} from "antd";
import * as SystemBackend from "./backend/SystemInfo";
import React from "react";
import * as Setting from "./Setting";
import i18next from "i18next";
class SystemInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
cpuUsage: [],
memUsed: 0,
memTotal: 0,
latestVersion: undefined,
intervalId: null,
href: "",
loading: true,
};
}
UNSAFE_componentWillMount() {
SystemBackend.getSystemInfo(this.props.account?.owner, this.props.account?.name).then(res => {
this.setState({
cpuUsage: res.cpu_usage,
memUsed: res.memory_used,
memTotal: res.memory_total,
loading: false,
});
const id = setInterval(() => {
SystemBackend.getSystemInfo(this.props.account?.owner, this.props.account?.name).then(res => {
this.setState({
cpuUsage: res.cpu_usage,
memUsed: res.memory_used,
memTotal: res.memory_total,
});
}).catch(error => {
Setting.showMessage("error", `System info failed to get: ${error}`);
});
}, 1000 * 3);
this.setState({intervalId: id});
}).catch(error => {
Setting.showMessage("error", `System info failed to get: ${error}`);
});
SystemBackend.getGitHubLatestReleaseVersion().then(res => {
const href = res && res.length >= 8 ? `https://github.com/casdoor/casdoor/commit/${res}` : "";
const versionText = res && res.length >= 8 ? res.substring(0, 8) : i18next.t("system:Unknown Version");
this.setState({latestVersion: versionText, href: href});
}).catch(err => {
Setting.showMessage("error", `get latest commit version failed: ${err}`);
});
}
componentWillUnmount() {
if (this.state.intervalId !== null) {
clearInterval(this.state.intervalId);
}
}
render() {
const CPUInfo = this.state.cpuUsage?.length > 0 ?
this.state.cpuUsage.map((usage, i) => {
return (
<Progress key={i} percent={Number(usage.toFixed(1))} />
);
}) : i18next.t("system:Get CPU Usage Failed");
const MemInfo = (
this.state.memUsed && this.state.memTotal && this.state.memTotal !== 0 ?
<div>
{Setting.getFriendlyFileSize(this.state.memUsed)} / {Setting.getFriendlyFileSize(this.state.memTotal)}
<br /> <br />
<Progress type="circle" percent={Number((Number(this.state.memUsed) / Number(this.state.memTotal) * 100).toFixed(2))} />
</div> : i18next.t("system:Get Memory Usage Failed")
);
return (
<Row>
<Col span={6}></Col>
<Col span={12}>
<Row gutter={[10, 10]}>
<Col span={12}>
<Card title={i18next.t("system:CPU Usage")} bordered={true} style={{textAlign: "center"}}>
{this.state.loading ? <Spin size="large" /> : CPUInfo}
</Card>
</Col>
<Col span={12}>
<Card title={i18next.t("system:Memory Usage")} bordered={true} style={{textAlign: "center"}}>
{this.state.loading ? <Spin size="large" /> : MemInfo}
</Card>
</Col>
</Row>
<Divider />
<Card title={i18next.t("system:About Casdoor")} bordered={true} style={{textAlign: "center"}}>
<div>{i18next.t("system:An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS")}</div>
GitHub: <a href="https://github.com/casdoor/casdoor">casdoor</a>
<br />
{i18next.t("system:Version")}: <a href={this.state.href}>{this.state.latestVersion}</a>
<br />
{i18next.t("system:Official Website")}: <a href="https://casdoor.org/">casdoor.org</a>
<br />
{i18next.t("system:Community")}: <a href="https://casdoor.org/#:~:text=Casdoor%20API-,Community,-GitHub">contact us</a>
</Card>
</Col>
<Col span={6}></Col>
</Row>
);
}
}
export default SystemInfo;

View File

@ -28,6 +28,7 @@ import OAuthWidget from "./common/OAuthWidget";
import SamlWidget from "./common/SamlWidget";
import SelectRegionBox from "./SelectRegionBox";
import WebAuthnCredentialTable from "./WebauthnCredentialTable";
import ManagedAccountTable from "./ManagedAccountTable";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
@ -543,7 +544,7 @@ class UserEditPage extends React.Component {
</Col>
</Row>
);
} else if(accountItem.name === "WebAuthn credentials") {
} else if (accountItem.name === "WebAuthn credentials") {
return (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
@ -554,6 +555,22 @@ class UserEditPage extends React.Component {
</Col>
</Row>
);
} else if (accountItem.name === "Managed accounts") {
return (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("user:Managed accounts"), i18next.t("user:Managed accounts"))} :
</Col>
<Col span={22} >
<ManagedAccountTable
title={i18next.t("user:Managed accounts")}
table={this.state.user.managedAccounts ?? []}
onUpdateTable={(table) => {this.updateUserField("managedAccounts", table);}}
applications={this.state.applications}
/>
</Col>
</Row>
);
}
}

View File

@ -505,6 +505,10 @@ class LoginPage extends React.Component {
renderSignedInBox() {
if (this.props.account === undefined || this.props.account === null) {
if (window !== window.parent) {
const message = {tag: "Casdoor", type: "SilentSignin", data: "user-not-logged-in"};
window.parent.postMessage(message, "*");
}
return null;
}
const application = this.getApplicationObj();

View File

@ -21,6 +21,7 @@ import * as Setting from "../Setting";
import i18next from "i18next";
import AffiliationSelect from "../common/AffiliationSelect";
import OAuthWidget from "../common/OAuthWidget";
import SelectRegionBox from "../SelectRegionBox";
class PromptPage extends React.Component {
constructor(props) {
@ -90,6 +91,16 @@ class PromptPage extends React.Component {
this.submitUserEdit(false);
}
updateUserFieldWithoutSubmit(key, value) {
value = this.parseUserField(key, value);
const user = this.state.user;
user[key] = value;
this.setState({
user: user,
});
}
renderAffiliation(application) {
if (!Setting.isAffiliationPrompted(application)) {
return null;
@ -120,6 +131,31 @@ class PromptPage extends React.Component {
application?.providers.filter(providerItem => Setting.isProviderPrompted(providerItem)).map((providerItem, index) => <OAuthWidget key={providerItem.name} labelSpan={6} user={this.state.user} application={application} providerItem={providerItem} account={this.props.account} onUnlinked={() => {return this.unlinked();}} />)
)
}
{
(application === null || this.state.user === null) ? null : (
application?.signupItems.filter(signupItem => Setting.isSignupItemPrompted(signupItem)).map((signupItem, index) => {
if (signupItem.name !== "Country/Region") {
return null;
}
return (
<Row key={signupItem.name} style={{marginTop: "20px", justifyContent: "space-between"}} >
<Col style={{marginTop: "5px"}} >
<span style={{marginLeft: "5px"}}>
{
i18next.t("user:Country/Region")
}:
</span>
</Col>
<Col >
<SelectRegionBox defaultValue={this.state.user.region} onChange={(value) => {
this.updateUserFieldWithoutSubmit("region", value);
}} />
</Col>
</Row>
);
})
)
}
</div>
</div>
);
@ -151,7 +187,7 @@ class PromptPage extends React.Component {
if (redirectUrl === "") {
redirectUrl = res.data2;
}
if (redirectUrl !== "") {
if (redirectUrl !== "" && redirectUrl !== null) {
Setting.goToLink(redirectUrl);
} else {
Setting.goToLogin(this, this.getApplicationObj());

View File

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

View File

@ -27,15 +27,23 @@ class SingleCard extends React.Component {
};
}
wrappedAsSilentSigninLink(link) {
if (link.startsWith("http")) {
link += link.includes("?") ? "&silentSignin=1" : "?silentSignin=1";
}
return link;
}
renderCardMobile(logo, link, title, desc, time, isSingle) {
const gridStyle = {
width: "100vw",
textAlign: "center",
cursor: "pointer",
};
const silentSigninLink = this.wrappedAsSilentSigninLink(link);
return (
<Card.Grid style={gridStyle} onClick={() => Setting.goToLinkSoft(this, link)}>
<Card.Grid style={gridStyle} onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}>
<img src={logo} alt="logo" height={60} style={{marginBottom: "20px"}} />
<Meta
title={title}
@ -46,6 +54,8 @@ class SingleCard extends React.Component {
}
renderCard(logo, link, title, desc, time, isSingle) {
const silentSigninLink = this.wrappedAsSilentSigninLink(link);
return (
<Col style={{paddingLeft: "20px", paddingRight: "20px", paddingBottom: "20px", marginBottom: "20px"}} span={6}>
<Card
@ -53,7 +63,7 @@ class SingleCard extends React.Component {
cover={
<img alt="logo" src={logo} style={{width: "100%", height: "210px", objectFit: "scale-down"}} />
}
onClick={() => Setting.goToLinkSoft(this, link)}
onClick={() => Setting.goToLinkSoft(this, silentSigninLink)}
style={isSingle ? {width: "320px"} : {width: "100%"}}
>
<Meta title={title} description={desc} />

View File

@ -20,11 +20,13 @@ import de from "./locales/de/data.json";
import ko from "./locales/ko/data.json";
import ru from "./locales/ru/data.json";
import ja from "./locales/ja/data.json";
import es from "./locales/es/data.json";
import * as Conf from "./Conf";
import * as Setting from "./Setting";
const resources = {
en: en,
es: es,
zh: zh,
fr: fr,
de: de,

View File

@ -13,7 +13,7 @@ code {
}
.logo {
background: url("https://cdn.casdoor.com/logo/casdoor-logo_1185x256.png");
background: url("https://cdn.casbin.org/img/casdoor-logo_1185x256.png");
background-size: 130px, 27px;
width: 130px;
height: 27px;

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"Timestamp": "Zeitstempel",
"Tokens": "Token",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "Aktionen",
"Actions - Tooltip": "Aktionen - Tooltip",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "Berechtigung bearbeiten",
"Effect": "Effekt",
"Effect - Tooltip": "Effekt - Tooltip",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "Ressourcentyp",
"Resource type - Tooltip": "Ressourcentyp - Tooltip",
"Resources": "Ressourcen",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "Primärschlüssel der Tabelle",
"Table primary key - Tooltip": "Primärschlüssel der Tabelle - Tooltip"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "Zugangs-Token",
"Authorization code": "Autorisierungscode",
@ -636,6 +657,7 @@
"Link": "Link",
"Location": "Standort",
"Location - Tooltip": "Standort - Tooltip",
"Managed accounts": "Managed accounts",
"Modify password...": "Passwort ändern...",
"New Email": "Neue E-Mail",
"New Password": "Neues Passwort",

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "Actions",
"Actions - Tooltip": "Actions - Tooltip",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "Edit Permission",
"Effect": "Effect",
"Effect - Tooltip": "Effect - Tooltip",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "Resource type",
"Resource type - Tooltip": "Resource type - Tooltip",
"Resources": "Resources",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key - Tooltip"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "Access token",
"Authorization code": "Authorization code",
@ -636,6 +657,7 @@
"Link": "Link",
"Location": "Location",
"Location - Tooltip": "Location - Tooltip",
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"New Email": "New Email",
"New Password": "New Password",

View File

@ -0,0 +1,685 @@
{
"account": {
"Login": "Iniciar sesión",
"Logout": "Cerrar sesión",
"My Account": "Mi cuenta",
"Sign Up": "Registrarme"
},
"application": {
"Copy SAML metadata URL": "Copiar SAML metadata URL",
"Copy prompt page URL": "Copy prompt page URL",
"Copy signin page URL": "Copiar URL de inicio de sesión",
"Copy signup page URL": "Copiar URL de registro de usuarios",
"Edit Application": "Editar Aplicación",
"Enable SAML compress": "Habilitar compresión SAML",
"Enable SAML compress - Tooltip": "Habilitar compresión SAML - Tooltip",
"Enable WebAuthn signin": "Habilitar inicio de sesión de WebAuthn",
"Enable WebAuthn signin - Tooltip": "Habilitar inicio de sesión de WebAuthn - Tooltip",
"Enable code signin": "Habilitar inicio de sesión por código",
"Enable code signin - Tooltip": "Habilitar inicio de sesión por código - Tooltip",
"Enable signin session - Tooltip": "Enable signin session - Tooltip",
"Enable signup": "Habilitar nuevos registros",
"Enable signup - Tooltip": "Habilitar nuevos registros - Tooltip",
"File uploaded successfully": "El archivo ha sido subido con éxito",
"Grant types": "Grant types",
"Grant types - Tooltip": "Grant types - Tooltip",
"New Application": "Nueva Aplicación",
"Password ON": "Constraseña ON",
"Password ON - Tooltip": "Constraseña ON - Tooltip",
"Please select a HTML file": "Seleccione un archivo HTML",
"Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Prompt page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Redirect URL": "URL de redirección",
"Redirect URLs": "URLs de redirección",
"Redirect URLs - Tooltip": "URL de redirección - Tooltip",
"Refresh token expire": "Expiración del Refresh Token",
"Refresh token expire - Tooltip": "Expiración del Refresh Token - Tooltip",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copiado al portapapeles con éxito",
"Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signin page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Signup items - Tooltip",
"Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Signup page URL copied to clipboard successfully, please paste it into the incognito window or another browser",
"Token expire": "Expiración del Token",
"Token expire - Tooltip": "Expiración del Token - Tooltip",
"Token format": "Formato del Token",
"Token format - Tooltip": "Formato del Token - Tooltip",
"rule": "rule"
},
"cert": {
"Bit size": "Tamaño del Bit",
"Bit size - Tooltip": "Tamaño del Bit - Tooltip",
"Certificate": "Certificado",
"Certificate - Tooltip": "Certificado - Tooltip",
"Certificate copied to clipboard successfully": "Certificado copiado al portapapeles con éxito",
"Copy certificate": "Copiar certificado",
"Copy private key": "Copiar clave privada",
"Crypto algorithm": "Algoritmo criptográfico",
"Crypto algorithm - Tooltip": "Algoritmo criptográfico - Tooltip",
"Download certificate": "Descargar certificado",
"Download private key": "Descargar clave privada",
"Edit Cert": "Editar certificado",
"Expire in years": "Expiración en años",
"Expire in years - Tooltip": "Expiración en años - Tooltip",
"New Cert": "Nuevo certificado",
"Private key": "Clave privada",
"Private key - Tooltip": "Clave privada - Tooltip",
"Private key copied to clipboard successfully": "Clave privada copiada al portapapeles con éxito",
"Scope": "Alcance",
"Scope - Tooltip": "Alcance - Tooltip",
"Type": "Tipo",
"Type - Tooltip": "Tipo - Tooltip"
},
"code": {
"Code You Received": "Código que recibiste",
"Email code": "Código de Email",
"Empty Code": "Código requerido",
"Enter your code": "Ingrese su código",
"Phone code": "Código de teléfono",
"Please input your phone verification code!": "Ingrese su código de verificación teléfonico!",
"Please input your verification code!": "Ingrese su código de verificación!",
"Send Code": "Enviar código",
"Sending Code": "Enviando código",
"Submit and complete": "Enviar y completar"
},
"forget": {
"Account": "Cuenta",
"Change Password": "Cambiar contraseña",
"Choose email or phone": "Elige email o teléfono",
"Confirm": "Confirmar",
"Next Step": "Siguiente paso",
"Password": "Contraseña",
"Please input your username!": "Por favor ingrese su nombre de usuario!",
"Reset": "Reiniciar",
"Retrieve password": "Recuperar Contraseña",
"Unknown forget type": "Tipo de olvido desconocido",
"Verify": "Verificar"
},
"general": {
"Action": "Acción",
"Adapter": "Adaptador",
"Adapter - Tooltip": "Adaptador - Tooltip",
"Add": "Agregar",
"Affiliation URL": "URL de Afiliación",
"Affiliation URL - Tooltip": "URL de Afiliación - Tooltip",
"Application": "Aplicación",
"Applications": "Aplicaciones",
"Applications that require authentication": "Aplicaciones que requieren autenticación",
"Avatar": "Avatar",
"Avatar - Tooltip": "Avatar - Tooltip",
"Back Home": "Volver al inicio",
"Cancel": "Cancelar",
"Captcha": "Captcha",
"Cert": "Certificado",
"Cert - Tooltip": "Certificado - Tooltip",
"Certs": "Certificados",
"Click to Upload": "Click para subir archivo",
"Client IP": "IP del Cliente",
"Created time": "Fecha de creación",
"Default avatar": "Avatar por defecto",
"Default avatar - Tooltip": "Avatar por defecto - Tooltip",
"Delete": "Eliminar",
"Description": "Descripción",
"Description - Tooltip": "Descripción - Tooltip",
"Display name": "Apodo",
"Display name - Tooltip": "Apodo - Tooltip",
"Down": "Bajar",
"Edit": "Editar",
"Email": "Email",
"Email - Tooltip": "Email - Tooltip",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon - Tooltip",
"First name": "Nombre",
"Forget URL": "URL de olvido",
"Forget URL - Tooltip": "URL de olvido - Tooltip",
"Home": "Inicio",
"Home - Tooltip": "Inicio - Tooltip",
"ID": "ID",
"ID - Tooltip": "ID - Tooltip",
"Is enabled": "Está habilitado",
"Is enabled - Tooltip": "Está habilitado - Tooltip",
"LDAPs": "LDAPs",
"LDAPs - Tooltip": "LDAPs - Tooltip",
"Last name": "Apellido",
"Logo": "Logo",
"Logo - Tooltip": "Logo - Tooltip",
"Master password": "Contraseña maestra",
"Master password - Tooltip": "Contraseña maestra - Tooltip",
"Method": "Metodo",
"Model": "Modelo",
"Model - Tooltip": "Modelo - Tooltip",
"Models": "Modelos",
"Name": "Nombre",
"Name - Tooltip": "Nombre - Tooltip",
"OAuth providers": "OAuth providers",
"Organization": "Organización",
"Organization - Tooltip": "Organización - Tooltip",
"Organizations": "Organizaciones",
"Password": "Contraseña",
"Password - Tooltip": "Contraseña - Tooltip",
"Password salt": "Password salt",
"Password salt - Tooltip": "Password salt - Tooltip",
"Password type": "Tipo de Contraseña",
"Password type - Tooltip": "Tipo de Contraseña - Tooltip",
"Payments": "Pagos",
"Permissions": "Permisos",
"Permissions - Tooltip": "Permisos - Tooltip",
"Phone": "Teléfono",
"Phone - Tooltip": "Teléfono - Tooltip",
"Phone prefix": "Prefijo teléfonico",
"Phone prefix - Tooltip": "Prefijo teléfonico - Tooltip",
"Preview": "Previsualizar",
"Preview - Tooltip": "Previsualizar - Tooltip",
"Products": "Productos",
"Provider": "Proveedor",
"Provider - Tooltip": "Proveedor - Tooltip",
"Providers": "Proveedores",
"Providers - Tooltip": "Proveedores - Tooltip",
"Real name": "Nombre real",
"Records": "Registros",
"Request URI": "Request URI",
"Resources": "Recursos",
"Roles": "Roles",
"Roles - Tooltip": "Roles - Tooltip",
"Save": "Guardar",
"Save & Exit": "Guardar & Volver",
"Signin URL": "URL de inicio de sesión",
"Signin URL - Tooltip": "URL de inicio de sesión - Tooltip",
"Signup URL": "URL de registro",
"Signup URL - Tooltip": "URL de registro - Tooltip",
"Signup application": "Aplicación de inicio de sesión",
"Signup application - Tooltip": "Aplicación de inicio de sesión - Tooltip",
"Sorry, the page you visited does not exist.": "Lo sentimos, la página que visitaste no existe.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Lo sentimos, el usuario que visitaste no existe o no estás autorizado para acceder.",
"Sorry, you do not have permission to access this page.": "Lo sentimos, no tienes permiso para acceder a esta página.",
"State": "Estado",
"State - Tooltip": "Estado - Tooltip",
"Swagger": "Swagger",
"Sync": "Sincronizador",
"Syncers": "Sincronizadores",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",
"URL - Tooltip": "URL - Tooltip",
"Up": "Subir",
"User": "Usuario",
"User - Tooltip": "Usuario - Tooltip",
"User containers": "Contenedores de usuarios",
"User type": "Tipo de usuario",
"User type - Tooltip": "Tipo de usuario - Tooltip",
"Users": "Usuarios",
"Users under all organizations": "Usuarios de todas las organizaciones",
"Webhooks": "Webhooks",
"{total} in total": "{total} en total"
},
"ldap": {
"Address": "Dirección",
"Admin": "Admin",
"Admin - Tooltip": "Admin - Tooltip",
"Admin Password": "Contraseña del admin",
"Admin Password - Tooltip": "Contraseña del admin - Tooltip",
"Auto Sync": "Sincronización automática",
"Auto Sync - Tooltip": "Sincronización automática - Tooltip",
"Base DN": "Base DN",
"Base DN - Tooltip": "Base DN - Tooltip",
"CN": "CN",
"Edit LDAP": "Editar LDAP",
"Email": "Email",
"Group Id": "Group Id",
"ID": "ID",
"Last Sync": "Última Sincronización",
"Phone": "Teléfono",
"Server": "Servidor",
"Server Host": "Host de Servidor",
"Server Host - Tooltip": "Host de Servidor - Tooltip",
"Server Name": "Nombre del Servidor",
"Server Name - Tooltip": "Nombre del Servidor - Tooltip",
"Server Port": "Puerto del servidor",
"Server Port - Tooltip": "Puerto del servidor - Tooltip",
"Sync": "Sincronizar",
"The Auto Sync option will sync all users to specify organization": "La opción de sincronización automática sincronizará todos los usuarios para la organización especificada.",
"UidNumber / Uid": "UidNumber / Uid"
},
"login": {
"Auto sign in": "Inicio de sesión automático",
"Continue with": "Continuar con",
"Email or phone": "Email o teléfono",
"Forgot password?": "¿Olvidó su contraseña?",
"Logging out...": "Cerrando su sesión...",
"No account?": "¿No estás registrado?",
"Or sign in with another account": "O inicia sesión con otra cuenta",
"Password": "Contraseña",
"Password - Tooltip": "Contraseña - Tooltip",
"Please input your code!": "¡Por favor ingrese su código!",
"Please input your password!": "¡Por favor ingrese su contraseña!",
"Please input your password, at least 6 characters!": "Su contraseña debe contener al menos 6 caracteres.",
"Please input your username, Email or phone!": "¡Ingrese su nombre de usuario, correo electrónico o teléfono!",
"Sign In": "Iniciar de sesión",
"Sign in with WebAuthn": "Iniciar de sesión con WebAuthn",
"Sign in with code": "Iniciar de sesión con código",
"Sign in with password": "Iniciar de sesión con contraseña",
"Sign in with {type}": "Iniciar de sesión con {type}",
"Signing in...": "Iniciando de sesión...",
"The input is not valid Email or Phone!": "El valor ingresado no es un Email o Teléfono válido!",
"To access": "Para ingresar",
"sign up now": "Regístrate ahora",
"username, Email or phone": "nombre de usuario, correo electrónico o teléfono"
},
"model": {
"Edit Model": "Editar Modelo",
"Model text": "Texto del modelo",
"Model text - Tooltip": "Texto del modelo - Tooltip",
"New Model": "Nuevo Modelo"
},
"organization": {
"Account items": "Items de la cuenta",
"Account items - Tooltip": "Items de la cuenta - Tooltip",
"Default avatar": "Avatar por defecto",
"Edit Organization": "Editar Organización",
"Favicon": "Favicon",
"Is profile public": "Es el perfil publico",
"Is profile public - Tooltip": "Es el perfil publico - Tooltip",
"New Organization": "Nueva Organización",
"Soft deletion": "Eliminación Soft",
"Soft deletion - Tooltip": "Eliminación Soft - Tooltip",
"Tags": "Etiquetas",
"Tags - Tooltip": "Etiquetas - Tooltip",
"Website URL": "URL del sitio web",
"Website URL - Tooltip": "URL del sitio web - Tooltip",
"modifyRule": "modifyRule",
"viewRule": "viewRule"
},
"payment": {
"Confirm your invoice information": "Confirma la información de tu factura",
"Currency": "Moneda",
"Currency - Tooltip": "Moneda - Tooltip",
"Download Invoice": "Descargar factura",
"Edit Payment": "Editar Pago",
"Individual": "Individual",
"Invoice URL": "URL de factura",
"Invoice URL - Tooltip": "URL de factura - Tooltip",
"Invoice actions": "Acciones de factura",
"Invoice actions - Tooltip": "Acciones de factura - Tooltip",
"Invoice remark": "Comentario de factura",
"Invoice remark - Tooltip": "Comentario de factura - Tooltip",
"Invoice tax ID": "Número de identificación fiscal de la factura",
"Invoice tax ID - Tooltip": "Número de identificación fiscal de la factura - Tooltip",
"Invoice title": "Titulo de factura",
"Invoice title - Tooltip": "Titulo de factura - Tooltip",
"Invoice type": "Tipo de factura",
"Invoice type - Tooltip": "Tipo de factura - Tooltip",
"Issue Invoice": "Emitir factura",
"Message": "Mensaje",
"Message - Tooltip": "Mensaje - Tooltip",
"New Payment": "Nuevo Pago",
"Organization": "Organización",
"Person Email": "Email de la persona",
"Person Email - Tooltip": "Email de la persona - Tooltip",
"Person ID card": "Documento de identidad de la persona",
"Person ID card - Tooltip": "Documento de identidad de la persona - Tooltip",
"Person name": "Nombre de la persona",
"Person name - Tooltip": "Nombre de la persona - Tooltip",
"Person phone": "Teléfono de la persona",
"Person phone - Tooltip": "Teléfono de la persona - Tooltip",
"Please carefully check your invoice information. Once the invoice is issued, it cannot be withdrawn or modified.": "Por favor revise cuidadosamente la información de su factura. Una vez emitida la factura, no podrá ser retirada ni modificada.",
"Please click the below button to return to the original website": "Haga clic en el botón de abajo para volver al sitio web original",
"Please pay the order first!": "¡Por favor pague la orden primero!",
"Price": "Precio",
"Price - Tooltip": "Precio - Tooltip",
"Processing...": "Procesando...",
"Product": "Producto",
"Product - Tooltip": "Producto - Tooltip",
"Result": "Resultado",
"Return to Website": "Volver al sitio web",
"State": "Estado",
"State - Tooltip": "Estado - Tooltip",
"The payment has failed": "El pago ha fallado",
"The payment is still under processing": "El pago aún está en proceso",
"Type": "Tipo",
"Type - Tooltip": "Tipo - Tooltip",
"You have successfully completed the payment": "Su pago se ha completado con éxito",
"please wait for a few seconds...": "por favor espere unos segundos...",
"the current state is": "el estado actual es"
},
"permission": {
"Actions": "Acciones",
"Actions - Tooltip": "Acciones - Tooltip",
"Approve time": "Fecha de aprobación",
"Approve time - Tooltip": "Fecha de aprobación - Tooltip",
"Approver": "Aprobador",
"Approver - Tooltip": "Aprobador - Tooltip",
"Edit Permission": "Editar Permiso",
"Effect": "Effect",
"Effect - Tooltip": "Effect - Tooltip",
"New Permission": "Nuevo Permiso",
"Resource type": "Tipo de recurso",
"Resource type - Tooltip": "Tipo de recurso - Tooltip",
"Resources": "Recursos",
"Resources - Tooltip": "Recursos - Tooltip",
"State": "Estado",
"State - Tooltip": "Estado - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
},
"product": {
"Alipay": "Alipay",
"Buy": "Comprar",
"Buy Product": "Comprar Producto",
"CNY": "CNY",
"Currency": "Moneda",
"Currency - Tooltip": "Moneda - Tooltip",
"Detail": "Detalle",
"Detail - Tooltip": "Detalle - Tooltip",
"Edit Product": "Editar Producto",
"Image": "Imagen",
"Image - Tooltip": "Imagen - Tooltip",
"New Product": "Nuevo producto",
"Pay": "Pago",
"Payment providers": "Pasarelas de pago",
"Payment providers - Tooltip": "Pasarelas de pago - Tooltip",
"Paypal": "Paypal",
"Placing order...": "Creando su pedido...",
"Price": "Precio",
"Price - Tooltip": "Precio - Tooltip",
"Quantity": "Cantidad",
"Quantity - Tooltip": "Cantidad - Tooltip",
"Return URL": "URL de retorno",
"Return URL - Tooltip": "URL de retorno - Tooltip",
"SKU": "SKU",
"Sold": "Agotado",
"Sold - Tooltip": "Agotado - Tooltip",
"Tag": "Etiqueta",
"Tag - Tooltip": "Etiqueta - Tooltip",
"Test buy page..": "Probar página de pago...",
"There is no payment channel for this product.": "No existe un canal de pago para este producto.",
"This product is currently not in sale.": "Este producto actualmente no está a la venta.",
"USD": "USD",
"WeChat Pay": "WeChat Pay"
},
"provider": {
"Access key": "Clave de acceso",
"Access key - Tooltip": "Clave de acceso - Tooltip",
"Agent ID": "ID del Agente",
"Agent ID - Tooltip": "ID del Agente - Tooltip",
"App ID": "App ID",
"App ID - Tooltip": "App ID - Tooltip",
"App key": "App key",
"App key - Tooltip": "App key - Tooltip",
"App secret": "App secret",
"AppSecret - Tooltip": "AppSecret - Tooltip",
"Auth URL": "Auth URL",
"Auth URL - Tooltip": "Auth URL - Tooltip",
"Bucket": "Bucket",
"Bucket - Tooltip": "Bucket - Tooltip",
"Can not parse Metadata": "Can not parse Metadata",
"Category": "Categoria",
"Category - Tooltip": "Categoria - Tooltip",
"Channel No.": "Channel No.",
"Channel No. - Tooltip": "Channel No. - Tooltip",
"Client ID": "Client ID",
"Client ID - Tooltip": "Client ID - Tooltip",
"Client ID 2": "Client ID 2",
"Client ID 2 - Tooltip": "Client ID 2 - Tooltip",
"Client secret": "Client secret",
"Client secret - Tooltip": "Client secret - Tooltip",
"Client secret 2": "Client secret 2",
"Client secret 2 - Tooltip": "Client secret 2 - Tooltip",
"Copy": "Copiar",
"Disable SSL": "Deshabilitar SSL",
"Disable SSL - Tooltip": "Deshabilitar SSL - Tooltip",
"Domain": "Dominio",
"Domain - Tooltip": "Dominio - Tooltip",
"Edit Provider": "Editar Proveedor",
"Email Content": "Contenido del Email",
"Email Content - Tooltip": "Contenido del Email - Tooltip",
"Email Title": "Titulo del Email",
"Email Title - Tooltip": "Titulo del Email - Tooltip",
"Endpoint": "Endpoint",
"Endpoint (Intranet)": "Endpoint (Intranet)",
"Host": "Host",
"Host - Tooltip": "Host - Tooltip",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL - Tooltip",
"Link copied to clipboard successfully": "Enlace copiado al portapapeles con éxito",
"Metadata": "Metadata",
"Metadata - Tooltip": "Metadata - Tooltip",
"Method": "Metodo",
"Method - Tooltip": "Metodo - Tooltip",
"Name": "Nombre",
"New Provider": "Nuevo Proveedor",
"Parse": "Parsear",
"Parse Metadata successfully": "Metadata parseada con éxito",
"Port": "Puerto",
"Port - Tooltip": "Puerto - Tooltip",
"Provider URL": "URL del Proveedor",
"Provider URL - Tooltip": "URL del Proveedor - Tooltip",
"Region ID": "Region ID",
"Region ID - Tooltip": "Region ID - Tooltip",
"Region endpoint for Internet": "Region endpoint for Internet",
"Region endpoint for Intranet": "Region endpoint for Intranet",
"SAML 2.0 Endpoint (HTTP)": "SAML 2.0 Endpoint (HTTP)",
"SMS account": "SMS account",
"SMS account - Tooltip": "SMS account - Tooltip",
"SP ACS URL": "SP ACS URL",
"SP ACS URL - Tooltip": "SP ACS URL - Tooltip",
"SP Entity ID": "SP Entity ID",
"Scene": "Scene",
"Scene - Tooltip": "Scene - Tooltip",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Secret access key": "Secret access key",
"Secret key": "Secret key",
"Secret key - Tooltip": "Secret key - Tooltip",
"SecretAccessKey - Tooltip": "SecretAccessKey - Tooltip",
"Send Test Email": "Enviar email de prueba",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Sign Name - Tooltip",
"Sign request": "Sign request",
"Sign request - Tooltip": "Sign request - Tooltip",
"Signin HTML": "Signin HTML",
"Signin HTML - Edit": "Signin HTML - Edit",
"Signin HTML - Tooltip": "Signin HTML - Tooltip",
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Signup HTML - Tooltip",
"Site key": "Site key",
"Site key - Tooltip": "Site key - Tooltip",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type - Tooltip",
"Template Code": "Código de plantilla",
"Template Code - Tooltip": "Código de plantilla - Tooltip",
"Terms of Use": "Términos de Uso",
"Terms of Use - Tooltip": "Términos de Uso - Tooltip",
"Test Connection": "Probar Conexión",
"Test Email": "Probar Email",
"Test Email - Tooltip": "Probar Email - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Tipo",
"Type - Tooltip": "Tipo - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL - Tooltip",
"alertType": "alertType",
"canSignIn": "canSignIn",
"canSignUp": "canSignUp",
"canUnlink": "canUnlink",
"prompted": "prompted",
"required": "required",
"visible": "visible"
},
"record": {
"Is Triggered": "Esta activado"
},
"resource": {
"Application": "Aplicación",
"Copy Link": "Copiar Link",
"File name": "Nombre del archivo",
"File size": "Tamaño del archivo",
"Format": "Formato",
"Link copied to clipboard successfully": "Enlace copiado al portapapeles con éxito",
"Parent": "Parent",
"Tag": "Etiqueta",
"Type": "Tipo",
"Upload a file...": "Subir archivo...",
"User": "Usuario"
},
"role": {
"Edit Role": "Editar Rol",
"New Role": "Nuevo Rol",
"Sub domains": "Sub dominios",
"Sub domains - Tooltip": "Sub dominios - Tooltip",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Sub roles - Tooltip",
"Sub users": "Sub usuarios",
"Sub users - Tooltip": "Sub usuarios - Tooltip"
},
"signup": {
"Accept": "Aceptar",
"Agreement": "Agreement",
"Confirm": "Confirmar",
"Decline": "Rechazar",
"Have account?": "¿Ya tienes una cuenta?",
"Please accept the agreement!": "Por favor, acepte el acuerdo!",
"Please click the below button to sign in": "Por favor, haga clic en el botón de abajo para iniciar sesión",
"Please confirm your password!": "Por favor, confirme su contraseña!",
"Please input the correct ID card number!": "¡Ingrese un documento de identidad correcto!",
"Please input your Email!": "Por favor, ingrese su Email!",
"Please input your ID card number!": "Por favor, ingrese su documento de identidad!",
"Please input your address!": "Por favor, ingrese su domicilio!",
"Please input your affiliation!": "Por favor, ingrese su afiliación!",
"Please input your display name!": "Por favor, ingrese su apodo!",
"Please input your first name!": "Por favor, ingrese su nombre!",
"Please input your last name!": "Por favor, ingrese su apellido!",
"Please input your phone number!": "Por favor, ingrese su número teléfonico!",
"Please input your real name!": "Por favor, ingrese un nombre real!",
"Please select your country/region!": "Por favor, seleccione su pais/region!",
"Terms of Use": "Términos de Uso",
"The input is not invoice Tax ID!": "El valor ingresado no es un número de identificación fiscal de factura!",
"The input is not invoice title!": "El valor ingresado no es el titulo de factura!",
"The input is not valid Email!": "El valor ingresado no es un Email válido!",
"The input is not valid Phone!": "El valor ingresado no es un Teléfono válido!",
"Username": "Nombre de usuario",
"Username - Tooltip": "Nombre de usuario - Tooltip",
"Your account has been created!": "¡Tu cuenta ha sido creada!",
"Your confirmed password is inconsistent with the password!": "¡La confirmación de su contraseña es inconsistente!",
"sign in now": "iniciar sesión ahora"
},
"syncer": {
"Affiliation table": "Tabla de afiliación",
"Affiliation table - Tooltip": "Tabla de afiliación - Tooltip",
"Avatar base URL": "Avatar base URL",
"Avatar base URL - Tooltip": "Avatar base URL - Tooltip",
"Casdoor column": "Casdoor column",
"Column name": "Nombre de columna",
"Column type": "Tipo de columna",
"Database": "Base de datos",
"Database - Tooltip": "Base de datos - Tooltip",
"Database type": "Tipo de base de datos",
"Database type - Tooltip": "Tipo de base de datos - Tooltip",
"Edit Syncer": "Editar Sincronizador",
"Error text": "Texto de Error",
"Error text - Tooltip": "Texto de Error - Tooltip",
"Is hashed": "Esta hashed?",
"New Syncer": "Nuevo Sincronizador",
"Sync interval": "Intervalo de sincronización",
"Sync interval - Tooltip": "Intervalo de sincronización - Tooltip",
"Table": "Tabla",
"Table - Tooltip": "Tabla - Tooltip",
"Table columns": "Columnas de la tabla",
"Table columns - Tooltip": "Columnas de la tabla - Tooltip",
"Table primary key": "Clave primaria de la tabla",
"Table primary key - Tooltip": "Clave primaria de la tabla - Tooltip"
},
"token": {
"Access token": "Token de acceso",
"Authorization code": "Código de autorización",
"Edit Token": "Editar Token",
"Expires in": "Expira en",
"New Token": "Nuevo Token",
"Scope": "Alcance",
"Token type": "Tipo del Token"
},
"user": {
"\" + destType + \" reset": "\" + destType + \" reset",
"3rd-party logins": "3rd-party logins",
"3rd-party logins - Tooltip": "3rd-party logins - Tooltip",
"Address": "Dirección",
"Address - Tooltip": "Dirección - Tooltip",
"Affiliation": "Afiliación",
"Affiliation - Tooltip": "Afiliación - Tooltip",
"Bio": "Acerca de vos",
"Bio - Tooltip": "Acerca de vos - Tooltip",
"Cancel": "Cancelar",
"Captcha Verify Failed": "Fallo la verificación del Captcha",
"Captcha Verify Success": "Captcha verificado con éxito",
"Code Sent": "Código enviado",
"Country/Region": "Pais/Región",
"Country/Region - Tooltip": "Pais/Región - Tooltip",
"Edit User": "Editar usuario",
"Empty input!": "Campo requerido!",
"Homepage": "Página de Inicio",
"Homepage - Tooltip": "Página de Inicio - Tooltip",
"ID card": "Documento de identidad",
"Input your email": "Ingrese su email",
"Input your phone number": "Ingrese su número teléfonico",
"Is admin": "Es admin",
"Is admin - Tooltip": "Es admin - Tooltip",
"Is deleted": "Esta Eliminado",
"Is deleted - Tooltip": "Esta Eliminado - Tooltip",
"Is forbidden": "Está prohibido",
"Is forbidden - Tooltip": "Está prohibido - Tooltip",
"Is global admin": "Es admin global",
"Is global admin - Tooltip": "Es admin global - Tooltip",
"Link": "Enlace",
"Location": "Ubicación",
"Location - Tooltip": "Ubicación - Tooltip",
"Modify password...": "Cambiar contraseña...",
"New Email": "Nuevo Email",
"New Password": "Nueva Contraseña",
"New User": "Nuevo usuario",
"New phone": "Nuevo teléfono",
"OK": "OK",
"Old Password": "Contraseña anterior",
"Password": "Contraseña",
"Password Set": "Password Set",
"Properties": "Propiedades",
"Re-enter New": "Reingrese de nuevo",
"Reset Email...": "Cambiar Email...",
"Reset Phone...": "Cambiar Phone...",
"Select a photo...": "Select a photo...",
"Set Password": "Cambiar contraseña",
"Set new profile picture": "Cambiar imagen de perfil",
"Set password...": "Cambiando contraseña...",
"Tag": "Etiqueta",
"Tag - Tooltip": "Etiqueta - Tooltip",
"Title": "Titulo",
"Title - Tooltip": "Titulo - Tooltip",
"Two passwords you typed do not match.": "La contraseña no coincide.",
"Unlink": "Desvincular",
"Upload (.xlsx)": "Subir archivo (.xlsx)",
"Upload a photo": "Subir foto",
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"webhook": {
"Content type": "Tipo de contenido",
"Content type - Tooltip": "Tipo de contenido - Tooltip",
"Edit Webhook": "Editar Webhook",
"Events": "Eventos",
"Events - Tooltip": "Eventos - Tooltip",
"Headers": "Cabeceras",
"Headers - Tooltip": "Cabeceras - Tooltip",
"Is user extended": "Es usuario extendido",
"Is user extended - Tooltip": "Es usuario extendido - Tooltip",
"Method": "Metodo",
"Method - Tooltip": "Metodo - Tooltip",
"Name": "Nombre",
"New Webhook": "Nuevo Webhook",
"URL": "URL",
"URL - Tooltip": "URL - Tooltip",
"Value": "Valor"
}
}

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Synchronisateurs",
"SysInfo": "SysInfo",
"Timestamp": "Horodatage",
"Tokens": "Jetons",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "Actions",
"Actions - Tooltip": "Actions - Info-bulle",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "Autorisation d'édition",
"Effect": "Effet",
"Effect - Tooltip": "Effet - Infobulle",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "Type de ressource",
"Resource type - Tooltip": "Type de ressource - infobulle",
"Resources": "Ressource",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "Clé primaire de la table",
"Table primary key - Tooltip": "Clé primaire du tableau - infobulle"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "Jeton d'accès",
"Authorization code": "Code d'autorisation",
@ -636,6 +657,7 @@
"Link": "Lier",
"Location": "Localisation",
"Location - Tooltip": "Localisation - Infobulle",
"Managed accounts": "Managed accounts",
"Modify password...": "Modifier le mot de passe...",
"New Email": "Nouvel e-mail",
"New Password": "Nouveau mot de passe",

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "システム情報",
"Timestamp": "タイムスタンプ",
"Tokens": "トークン",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "アクション",
"Actions - Tooltip": "アクション → ツールチップ",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "権限を編集",
"Effect": "効果",
"Effect - Tooltip": "エフェクト - ツールチップ",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "リソースタイプ",
"Resource type - Tooltip": "リソースタイプ - ツールチップ",
"Resources": "リソース",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "テーブルのプライマリキー",
"Table primary key - Tooltip": "テーブルのプライマリキー - ツールチップ"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "アクセストークン",
"Authorization code": "認証コード",
@ -636,6 +657,7 @@
"Link": "リンク",
"Location": "場所",
"Location - Tooltip": "場所 → ツールチップ",
"Managed accounts": "Managed accounts",
"Modify password...": "パスワードを変更...",
"New Email": "新しいメール",
"New Password": "新しいパスワード",

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Syncers",
"SysInfo": "SysInfo",
"Timestamp": "Timestamp",
"Tokens": "Tokens",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "Actions",
"Actions - Tooltip": "Actions - Tooltip",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "Edit Permission",
"Effect": "Effect",
"Effect - Tooltip": "Effect - Tooltip",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "Resource type",
"Resource type - Tooltip": "Resource type - Tooltip",
"Resources": "Resources",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "Table primary key",
"Table primary key - Tooltip": "Table primary key - Tooltip"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "Access token",
"Authorization code": "Authorization code",
@ -636,6 +657,7 @@
"Link": "Link",
"Location": "Location",
"Location - Tooltip": "Location - Tooltip",
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"New Email": "New Email",
"New Password": "New Password",

View File

@ -198,6 +198,7 @@
"Swagger": "Swagger",
"Sync": "Sync",
"Syncers": "Синхронизаторы",
"SysInfo": "Информация о системе",
"Timestamp": "Отметка времени",
"Tokens": "Жетоны",
"URL": "URL",
@ -345,14 +346,20 @@
"permission": {
"Actions": "Действия",
"Actions - Tooltip": "Действия - Подсказка",
"Admin": "Admin",
"Allow": "Allow",
"Approve time": "Approve time",
"Approve time - Tooltip": "Approve time - Tooltip",
"Approved": "Approved",
"Approver": "Approver",
"Approver - Tooltip": "Approver - Tooltip",
"Deny": "Deny",
"Edit Permission": "Изменить права доступа",
"Effect": "Эффект",
"Effect - Tooltip": "Эффект - Подсказка",
"New Permission": "New Permission",
"Pending": "Pending",
"Read": "Read",
"Resource type": "Тип ресурса",
"Resource type - Tooltip": "Тип ресурса - Подсказка",
"Resources": "Ресурсы",
@ -360,7 +367,9 @@
"State": "State",
"State - Tooltip": "State - Tooltip",
"Submitter": "Submitter",
"Submitter - Tooltip": "Submitter - Tooltip"
"Submitter - Tooltip": "Submitter - Tooltip",
"TreeNode": "TreeNode",
"Write": "Write"
},
"product": {
"Alipay": "Alipay",
@ -593,6 +602,18 @@
"Table primary key": "Основной ключ таблицы",
"Table primary key - Tooltip": "Основная таблица - Подсказка"
},
"system": {
"About Casdoor": "About Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS",
"CPU Usage": "CPU Usage",
"Community": "Community",
"Get CPU Usage Failed": "Get CPU Usage Failed",
"Get Memory Usage Failed": "Get Memory Usage Failed",
"Memory Usage": "Memory Usage",
"Official Website": "Official Website",
"Unknown Version": "Unknown Version",
"Version": "Version"
},
"token": {
"Access token": "Маркер доступа",
"Authorization code": "Код авторизации",
@ -636,6 +657,7 @@
"Link": "Ссылка",
"Location": "Местоположение",
"Location - Tooltip": "Расположение - Подсказка",
"Managed accounts": "Managed accounts",
"Modify password...": "Изменить пароль...",
"New Email": "Новое письмо",
"New Password": "Новый пароль",

View File

@ -198,6 +198,7 @@
"Swagger": "API文档",
"Sync": "同步",
"Syncers": "同步器",
"SysInfo": "系统信息",
"Timestamp": "时间戳",
"Tokens": "令牌",
"URL": "链接",
@ -345,14 +346,20 @@
"permission": {
"Actions": "动作",
"Actions - Tooltip": "授权的动作",
"Admin": "管理员权限",
"Allow": "允许",
"Approve time": "审批时间",
"Approve time - Tooltip": "该授权被审批通过的时间",
"Approved": "审批通过",
"Approver": "审批者",
"Approver - Tooltip": "审批通过该授权的人",
"Deny": "拒绝",
"Edit Permission": "编辑权限",
"Effect": "效果",
"Effect - Tooltip": "允许还是拒绝",
"New Permission": "添加权限",
"Pending": "待审批",
"Read": "读权限",
"Resource type": "资源类型",
"Resource type - Tooltip": "授权资源的类型",
"Resources": "资源",
@ -360,7 +367,9 @@
"State": "审批状态",
"State - Tooltip": "该授权现在的状态",
"Submitter": "申请者",
"Submitter - Tooltip": "申请该授权的人"
"Submitter - Tooltip": "申请该授权的人",
"TreeNode": "树节点",
"Write": "写权限"
},
"product": {
"Alipay": "支付宝",
@ -593,6 +602,18 @@
"Table primary key": "表主键",
"Table primary key - Tooltip": "表主键如id"
},
"system": {
"About Casdoor": "关于 Casdoor",
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "一个支持 OAuth 2.0、OIDC、SAML 和 CAS 的 Web UI 的身份和访问管理 (IAM)/单点登录 (SSO) 平台",
"CPU Usage": "CPU使用率",
"Community": "社区",
"Get CPU Usage Failed": "获取CPU使用率失败",
"Get Memory Usage Failed": "获取内存使用率失败",
"Memory Usage": "内存使用率",
"Official Website": "官方网站",
"Unknown Version": "未知版本",
"Version": "版本"
},
"token": {
"Access token": "访问令牌",
"Authorization code": "授权码",
@ -636,6 +657,7 @@
"Link": "绑定",
"Location": "城市",
"Location - Tooltip": "居住地址所在的城市",
"Managed accounts": "托管账户",
"Modify password...": "编辑密码...",
"New Email": "新邮箱",
"New Password": "新密码",