mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-16 10:43:35 +08:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
c50042c85a | |||
ef4c3833a4 | |||
67a5adf585 | |||
08a1e7ae32 | |||
7d979cbaf0 | |||
80c0940e30 | |||
a4fe2a6485 | |||
8e9ed1205b | |||
a341c65bb1 | |||
91fa024f0b | |||
aedef1eea1 | |||
70f2988f09 | |||
2dcdfbe6d3 | |||
c92d34e27c | |||
dfbf7753c3 |
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
@ -138,9 +141,9 @@ func (c *ApiController) SetSessionData(s *SessionData) {
|
||||
|
||||
func wrapActionResponse(affected bool) *Response {
|
||||
if affected {
|
||||
return &Response{Status: "ok", Msg: ""}
|
||||
return &Response{Status: "ok", Msg: "", Data: "Affected"}
|
||||
} else {
|
||||
return &Response{Status: "error", Msg: "this operation has no effect"}
|
||||
return &Response{Status: "ok", Msg: "", Data: "Unaffected"}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -48,6 +48,24 @@ func (c *ApiController) GetPermissions() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPermissionsBySubmitter
|
||||
// @Title GetPermissionsBySubmitter
|
||||
// @Tag Permission API
|
||||
// @Description get permissions by submitter
|
||||
// @Success 200 {array} object.Permission The Response object
|
||||
// @router /get-permissions-by-submitter [get]
|
||||
func (c *ApiController) GetPermissionsBySubmitter() {
|
||||
userId, ok := c.RequireSignedIn()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
owner, username := util.GetOwnerAndNameFromId(userId)
|
||||
permissions := object.GetPermissionsBySubmitter(owner, username)
|
||||
c.ResponseOk(permissions, len(permissions))
|
||||
return
|
||||
}
|
||||
|
||||
// GetPermission
|
||||
// @Title GetPermission
|
||||
// @Tag Permission API
|
||||
@ -76,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))
|
||||
@ -94,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))
|
||||
@ -112,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))
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
78
controllers/system_info.go
Normal file
78
controllers/system_info.go
Normal 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 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")
|
||||
}
|
||||
|
||||
cpuUsage, err := util.GetCpuUsage()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
}
|
||||
|
||||
memoryUsed, memoryTotal, err := util.GetMemoryUsage()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
c.Data["json"] = version
|
||||
c.ServeJSON()
|
||||
}
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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))
|
||||
|
9
go.mod
9
go.mod
@ -10,7 +10,7 @@ require (
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/casbin/casbin/v2 v2.30.1
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1
|
||||
github.com/casdoor/go-sms-sender v0.2.0
|
||||
github.com/casdoor/go-sms-sender v0.3.0
|
||||
github.com/casdoor/goth v1.69.0-FIX2
|
||||
github.com/casdoor/oss v1.2.0
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
@ -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
|
||||
|
32
go.sum
32
go.sum
@ -98,8 +98,8 @@ github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeK
|
||||
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1 h1:BkpIxRHKa0s3bSMx173PpuU7oTs+Zw7XmD0BIta0HGM=
|
||||
github.com/casbin/xorm-adapter/v2 v2.5.1/go.mod h1:AeH4dBKHC9/zYxzdPVHhPDzF8LYLqjDdb767CWJoV54=
|
||||
github.com/casdoor/go-sms-sender v0.2.0 h1:52bin4EBOPzOee64s9UK7jxd22FODvT9/+Y/Z+PSHpg=
|
||||
github.com/casdoor/go-sms-sender v0.2.0/go.mod h1:fsZsNnALvFIo+HFcE1U/oCQv4ZT42FdglXKMsEm3WSk=
|
||||
github.com/casdoor/go-sms-sender v0.3.0 h1:c4bWVcKZhO2L3Xu1oy7aeVkCK6HRJkW/b5K1xU9mV60=
|
||||
github.com/casdoor/go-sms-sender v0.3.0/go.mod h1:fsZsNnALvFIo+HFcE1U/oCQv4ZT42FdglXKMsEm3WSk=
|
||||
github.com/casdoor/goth v1.69.0-FIX2 h1:RgfIMkL9kekylgxHHK2ZY8ASAwOGns2HVlaBwLu7Bcs=
|
||||
github.com/casdoor/goth v1.69.0-FIX2/go.mod h1:Om55nRo8CkeDkPSNBbzXW4G5uI28ZUkSk5S69dPek3s=
|
||||
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
|
||||
@ -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=
|
||||
|
@ -18,6 +18,8 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/casdoor/casdoor/cred"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@ -29,6 +31,11 @@ var (
|
||||
reFieldWhiteList *regexp.Regexp
|
||||
)
|
||||
|
||||
const (
|
||||
SigninWrongTimesLimit = 5
|
||||
LastSignWrongTimeDuration = time.Minute * 15
|
||||
)
|
||||
|
||||
func init() {
|
||||
reWhiteSpace, _ = regexp.Compile(`\s`)
|
||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||
@ -42,11 +49,25 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
||||
if application.IsSignupItemVisible("Username") {
|
||||
if len(username) <= 1 {
|
||||
return "username must have at least 2 characters"
|
||||
} else if reWhiteSpace.MatchString(username) {
|
||||
}
|
||||
if unicode.IsDigit(rune(username[0])) {
|
||||
return "username cannot start with a digit"
|
||||
}
|
||||
if util.IsEmailValid(username) {
|
||||
return "username cannot be an email address"
|
||||
}
|
||||
if reWhiteSpace.MatchString(username) {
|
||||
return "username cannot contain white spaces"
|
||||
} else if HasUserByField(organization.Name, "name", username) {
|
||||
}
|
||||
if HasUserByField(organization.Name, "name", username) {
|
||||
return "username already exists"
|
||||
}
|
||||
if HasUserByField(organization.Name, "email", email) {
|
||||
return "email already exists"
|
||||
}
|
||||
if HasUserByField(organization.Name, "phone", phone) {
|
||||
return "phone already exists"
|
||||
}
|
||||
}
|
||||
|
||||
if len(password) <= 5 {
|
||||
@ -112,7 +133,32 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
||||
return ""
|
||||
}
|
||||
|
||||
func checkSigninErrorTimes(user *User) string {
|
||||
if user.SigninWrongTimes >= SigninWrongTimesLimit {
|
||||
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
|
||||
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
|
||||
seconds := int(LastSignWrongTimeDuration.Seconds() - passedTime.Seconds())
|
||||
|
||||
// deny the login if the error times is greater than the limit and the last login time is less than the duration
|
||||
if seconds > 0 {
|
||||
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", seconds/60, seconds%60)
|
||||
}
|
||||
|
||||
// reset the error times
|
||||
user.SigninWrongTimes = 0
|
||||
|
||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, user.IsGlobalAdmin)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func CheckPassword(user *User, password string) string {
|
||||
// check the login error times
|
||||
if msg := checkSigninErrorTimes(user); msg != "" {
|
||||
return msg
|
||||
}
|
||||
|
||||
organization := GetOrganizationByUser(user)
|
||||
if organization == nil {
|
||||
return "organization does not exist"
|
||||
@ -122,14 +168,17 @@ func CheckPassword(user *User, password string) string {
|
||||
if credManager != nil {
|
||||
if organization.MasterPassword != "" {
|
||||
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
|
||||
resetUserSigninErrorTimes(user)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
if credManager.IsPasswordCorrect(password, user.Password, user.PasswordSalt, organization.PasswordSalt) {
|
||||
resetUserSigninErrorTimes(user)
|
||||
return ""
|
||||
}
|
||||
return "password incorrect"
|
||||
|
||||
return recordSigninErrorInfo(user)
|
||||
} else {
|
||||
return fmt.Sprintf("unsupported password type: %s", organization.PasswordType)
|
||||
}
|
||||
|
@ -14,7 +14,11 @@
|
||||
|
||||
package object
|
||||
|
||||
import "regexp"
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
var reRealName *regexp.Regexp
|
||||
|
||||
@ -29,3 +33,32 @@ func init() {
|
||||
func isValidRealName(s string) bool {
|
||||
return reRealName.MatchString(s)
|
||||
}
|
||||
|
||||
func resetUserSigninErrorTimes(user *User) {
|
||||
// if the password is correct and wrong times is not zero, reset the error times
|
||||
if user.SigninWrongTimes == 0 {
|
||||
return
|
||||
}
|
||||
user.SigninWrongTimes = 0
|
||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
||||
}
|
||||
|
||||
func recordSigninErrorInfo(user *User) string {
|
||||
// increase failed login count
|
||||
user.SigninWrongTimes++
|
||||
|
||||
if user.SigninWrongTimes >= SigninWrongTimesLimit {
|
||||
// record the latest failed login time
|
||||
user.LastSigninWrongTime = time.Now().UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// update user
|
||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
||||
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
|
||||
if leftChances > 0 {
|
||||
return fmt.Sprintf("password is incorrect, you have %d remaining chances", leftChances)
|
||||
}
|
||||
|
||||
// don't show the chance error message if the user has no chance left
|
||||
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes and try again", int(LastSignWrongTimeDuration.Minutes()))
|
||||
}
|
||||
|
@ -251,6 +251,7 @@ func initBuiltInPermission() {
|
||||
DisplayName: "Built-in Permission",
|
||||
Users: []string{"built-in/admin"},
|
||||
Roles: []string{},
|
||||
Domains: []string{},
|
||||
ResourceType: "Application",
|
||||
Resources: []string{"app-built-in"},
|
||||
Actions: []string{"Read", "Write", "Admin"},
|
||||
|
@ -27,16 +27,22 @@ type Permission struct {
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
|
||||
Users []string `xorm:"mediumtext" json:"users"`
|
||||
Roles []string `xorm:"mediumtext" json:"roles"`
|
||||
Users []string `xorm:"mediumtext" json:"users"`
|
||||
Roles []string `xorm:"mediumtext" json:"roles"`
|
||||
Domains []string `xorm:"mediumtext" json:"domains"`
|
||||
|
||||
Model string `xorm:"varchar(100)" json:"model"`
|
||||
Adapter string `xorm:"varchar(100)" json:"adapter"`
|
||||
ResourceType string `xorm:"varchar(100)" json:"resourceType"`
|
||||
Resources []string `xorm:"mediumtext" json:"resources"`
|
||||
Actions []string `xorm:"mediumtext" json:"actions"`
|
||||
Effect string `xorm:"varchar(100)" json:"effect"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
||||
Approver string `xorm:"varchar(100)" json:"approver"`
|
||||
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
}
|
||||
|
||||
type PermissionRule struct {
|
||||
@ -47,6 +53,7 @@ type PermissionRule struct {
|
||||
V3 string `xorm:"varchar(100) index not null default ''" json:"v3"`
|
||||
V4 string `xorm:"varchar(100) index not null default ''" json:"v4"`
|
||||
V5 string `xorm:"varchar(100) index not null default ''" json:"v5"`
|
||||
Id string `xorm:"varchar(100) index not null default ''" json:"id"`
|
||||
}
|
||||
|
||||
func GetPermissionCount(owner, field, value string) int {
|
||||
@ -117,6 +124,15 @@ func UpdatePermission(id string, permission *Permission) bool {
|
||||
|
||||
if affected != 0 {
|
||||
removePolicies(oldPermission)
|
||||
if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter {
|
||||
isEmpty, _ := adapter.Engine.IsTableEmpty(oldPermission.Adapter)
|
||||
if isEmpty {
|
||||
err = adapter.Engine.DropTables(oldPermission.Adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
addPolicies(permission)
|
||||
}
|
||||
|
||||
@ -144,6 +160,15 @@ func DeletePermission(permission *Permission) bool {
|
||||
|
||||
if affected != 0 {
|
||||
removePolicies(permission)
|
||||
if permission.Adapter != "" && permission.Adapter != "permission_rule" {
|
||||
isEmpty, _ := adapter.Engine.IsTableEmpty(permission.Adapter)
|
||||
if isEmpty {
|
||||
err = adapter.Engine.DropTables(permission.Adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
@ -162,3 +187,23 @@ func GetPermissionsByUser(userId string) []*Permission {
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
||||
func GetPermissionsByRole(roleId string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Where("roles like ?", "%"+roleId+"%").Find(&permissions)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
||||
func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Submitter: submitter})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
@ -24,8 +24,12 @@ import (
|
||||
)
|
||||
|
||||
func getEnforcer(permission *Permission) *casbin.Enforcer {
|
||||
tableName := "permission_rule"
|
||||
if len(permission.Adapter) != 0 {
|
||||
tableName = permission.Adapter
|
||||
}
|
||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "permission_rule", tableNamePrefix, true)
|
||||
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), tableName, tableNamePrefix, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -35,13 +39,16 @@ func getEnforcer(permission *Permission) *casbin.Enforcer {
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = permission, sub, obj, act
|
||||
p = sub, obj, act
|
||||
|
||||
[role_definition]
|
||||
g = _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`
|
||||
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
|
||||
permissionModel := getModel(permission.Owner, permission.Model)
|
||||
if permissionModel != nil {
|
||||
modelText = permissionModel.ModelText
|
||||
@ -56,36 +63,71 @@ m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = enforcer.LoadFilteredPolicy(xormadapter.Filter{V0: []string{permission.GetId()}})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return enforcer
|
||||
}
|
||||
|
||||
func getPolicies(permission *Permission) [][]string {
|
||||
func getPolicies(permission *Permission) ([][]string, [][]string) {
|
||||
var policies [][]string
|
||||
var groupingPolicies [][]string
|
||||
domainExist := len(permission.Domains) > 0
|
||||
for _, user := range permission.Users {
|
||||
for _, resource := range permission.Resources {
|
||||
for _, action := range permission.Actions {
|
||||
policies = append(policies, []string{permission.GetId(), user, resource, strings.ToLower(action)})
|
||||
if domainExist {
|
||||
for _, domain := range permission.Domains {
|
||||
policies = append(policies, []string{user, domain, resource, strings.ToLower(action)})
|
||||
}
|
||||
} else {
|
||||
policies = append(policies, []string{user, resource, strings.ToLower(action)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, role := range permission.Roles {
|
||||
roleObj := GetRole(role)
|
||||
for _, subUser := range roleObj.Users {
|
||||
if domainExist {
|
||||
for _, domain := range permission.Domains {
|
||||
groupingPolicies = append(groupingPolicies, []string{subUser, domain, role})
|
||||
}
|
||||
} else {
|
||||
groupingPolicies = append(groupingPolicies, []string{subUser, role})
|
||||
}
|
||||
}
|
||||
for _, subRole := range roleObj.Roles {
|
||||
if domainExist {
|
||||
for _, domain := range permission.Domains {
|
||||
groupingPolicies = append(groupingPolicies, []string{subRole, domain, role})
|
||||
}
|
||||
} else {
|
||||
groupingPolicies = append(groupingPolicies, []string{subRole, role})
|
||||
}
|
||||
}
|
||||
for _, resource := range permission.Resources {
|
||||
for _, action := range permission.Actions {
|
||||
policies = append(policies, []string{permission.GetId(), role, resource, strings.ToLower(action)})
|
||||
if domainExist {
|
||||
for _, domain := range permission.Domains {
|
||||
policies = append(policies, []string{role, domain, resource, strings.ToLower(action)})
|
||||
}
|
||||
} else {
|
||||
policies = append(policies, []string{role, resource, strings.ToLower(action)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return policies
|
||||
return policies, groupingPolicies
|
||||
}
|
||||
|
||||
func addPolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
policies := getPolicies(permission)
|
||||
policies, groupingPolicies := getPolicies(permission)
|
||||
|
||||
if len(groupingPolicies) > 0 {
|
||||
_, err := enforcer.AddGroupingPolicies(groupingPolicies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := enforcer.AddPolicies(policies)
|
||||
if err != nil {
|
||||
@ -95,17 +137,25 @@ func addPolicies(permission *Permission) {
|
||||
|
||||
func removePolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
policies, groupingPolicies := getPolicies(permission)
|
||||
|
||||
_, err := enforcer.RemoveFilteredPolicy(0, permission.GetId())
|
||||
if len(groupingPolicies) > 0 {
|
||||
_, err := enforcer.RemoveGroupingPolicies(groupingPolicies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := enforcer.RemovePolicies(policies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Enforce(userId string, permissionRule *PermissionRule) bool {
|
||||
permission := GetPermission(permissionRule.V0)
|
||||
permission := GetPermission(permissionRule.Id)
|
||||
enforcer := getEnforcer(permission)
|
||||
allow, err := enforcer.Enforce(userId, permissionRule.V2, permissionRule.V3)
|
||||
allow, err := enforcer.Enforce(userId, permissionRule.V1, permissionRule.V2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -115,9 +165,9 @@ func Enforce(userId string, permissionRule *PermissionRule) bool {
|
||||
func BatchEnforce(userId string, permissionRules []PermissionRule) []bool {
|
||||
var requests [][]interface{}
|
||||
for _, permissionRule := range permissionRules {
|
||||
requests = append(requests, []interface{}{userId, permissionRule.V2, permissionRule.V3})
|
||||
requests = append(requests, []interface{}{userId, permissionRule.V1, permissionRule.V2})
|
||||
}
|
||||
permission := GetPermission(permissionRules[0].V0)
|
||||
permission := GetPermission(permissionRules[0].Id)
|
||||
enforcer := getEnforcer(permission)
|
||||
allow, err := enforcer.BatchEnforce(requests)
|
||||
if err != nil {
|
||||
@ -126,30 +176,30 @@ func BatchEnforce(userId string, permissionRules []PermissionRule) []bool {
|
||||
return allow
|
||||
}
|
||||
|
||||
func getAllValues(userId string, sec string, fieldIndex int) []string {
|
||||
func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) []string {
|
||||
permissions := GetPermissionsByUser(userId)
|
||||
for _, role := range GetAllRoles(userId) {
|
||||
permissions = append(permissions, GetPermissionsByRole(role)...)
|
||||
}
|
||||
|
||||
var values []string
|
||||
for _, permission := range permissions {
|
||||
enforcer := getEnforcer(permission)
|
||||
enforcer.ClearPolicy()
|
||||
err := enforcer.LoadFilteredPolicy(xormadapter.Filter{V0: []string{permission.GetId()}, V1: []string{userId}})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, value := range enforcer.GetModel().GetValuesForFieldInPolicyAllTypes(sec, fieldIndex) {
|
||||
values = append(values, value)
|
||||
}
|
||||
values = append(values, fn(enforcer)...)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func GetAllObjects(userId string) []string {
|
||||
return getAllValues(userId, "p", 2)
|
||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
||||
return enforcer.GetAllObjects()
|
||||
})
|
||||
}
|
||||
|
||||
func GetAllActions(userId string) []string {
|
||||
return getAllValues(userId, "p", 3)
|
||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
||||
return enforcer.GetAllActions()
|
||||
})
|
||||
}
|
||||
|
||||
func GetAllRoles(userId string) []string {
|
||||
|
@ -29,6 +29,7 @@ type Role struct {
|
||||
|
||||
Users []string `xorm:"mediumtext" json:"users"`
|
||||
Roles []string `xorm:"mediumtext" json:"roles"`
|
||||
Domains []string `xorm:"mediumtext" json:"domains"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
}
|
||||
|
||||
@ -88,7 +89,8 @@ func GetRole(id string) *Role {
|
||||
|
||||
func UpdateRole(id string, role *Role) bool {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if getRole(owner, name) == nil {
|
||||
oldRole := getRole(owner, name)
|
||||
if oldRole == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,9 @@ type User struct {
|
||||
|
||||
Roles []*Role `json:"roles"`
|
||||
Permissions []*Permission `json:"permissions"`
|
||||
|
||||
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||
}
|
||||
|
||||
type Userinfo struct {
|
||||
@ -376,6 +379,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
||||
"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",
|
||||
"signin_wrong_times", "last_signin_wrong_time",
|
||||
}
|
||||
}
|
||||
if isGlobalAdmin {
|
||||
|
@ -78,6 +78,7 @@ func initAPI() {
|
||||
beego.Router("/api/delete-role", &controllers.ApiController{}, "POST:DeleteRole")
|
||||
|
||||
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
|
||||
beego.Router("/api/get-permissions-by-submitter", &controllers.ApiController{}, "GET:GetPermissionsBySubmitter")
|
||||
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission")
|
||||
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
|
||||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
||||
@ -201,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")
|
||||
}
|
||||
|
36
storage/minio_s3.go
Normal file
36
storage/minio_s3.go
Normal 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
|
||||
}
|
@ -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
78
util/system.go
Normal 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
33
util/sysytem_test.go
Normal 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)
|
||||
}
|
@ -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});
|
||||
}
|
||||
@ -385,13 +388,17 @@ class App extends Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
res.push(
|
||||
<Menu.Item key="/permissions">
|
||||
<Link to="/permissions">
|
||||
{i18next.t("general:Permissions")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
res.push(
|
||||
<Menu.Item key="/permissions">
|
||||
<Link to="/permissions">
|
||||
{i18next.t("general:Permissions")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
|
||||
if (Setting.isAdminUser(this.state.account)) {
|
||||
res.push(
|
||||
<Menu.Item key="/models">
|
||||
<Link to="/models">
|
||||
@ -474,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"}>
|
||||
@ -556,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>
|
||||
@ -687,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>
|
||||
|
@ -22,6 +22,7 @@ import i18next from "i18next";
|
||||
import * as RoleBackend from "./backend/RoleBackend";
|
||||
import * as ModelBackend from "./backend/ModelBackend";
|
||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||
import moment from "moment/moment";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
@ -186,6 +187,16 @@ class PermissionEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Adapter"), i18next.t("general:Adapter - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.permission.adapter} onChange={e => {
|
||||
this.updatePermissionField("adapter", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub users"), i18next.t("role:Sub users - Tooltip"))} :
|
||||
@ -210,6 +221,20 @@ class PermissionEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub domains"), i18next.t("role:Sub domains - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: "100%"}} value={this.state.permission.domains} onChange={(value => {
|
||||
this.updatePermissionField("domains", value);
|
||||
})}>
|
||||
{
|
||||
this.state.permission.domains.map((domain, index) => <Option key={index} value={domain}>{domain}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Resource type"), i18next.t("permission:Resource type - Tooltip"))} :
|
||||
@ -283,11 +308,89 @@ class PermissionEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Submitter"), i18next.t("permission:Submitter - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.permission.submitter} onChange={e => {
|
||||
this.updatePermissionField("submitter", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Approver"), i18next.t("permission:Approver - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.permission.approver} onChange={e => {
|
||||
this.updatePermissionField("approver", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:Approve time"), i18next.t("permission:Approve time - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={Setting.getFormattedDate(this.state.permission.approveTime)} onChange={e => {
|
||||
this.updatePermissionField("approveTime", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("permission:State"), i18next.t("permission:State - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select disabled={!Setting.isLocalAdminUser(this.props.account)} virtual={false} style={{width: "100%"}} value={this.state.permission.state} onChange={(value => {
|
||||
if (this.state.permission.state !== value) {
|
||||
if (value === "Approved") {
|
||||
this.updatePermissionField("approver", this.props.account.name);
|
||||
this.updatePermissionField("approveTime", moment().format());
|
||||
} else {
|
||||
this.updatePermissionField("approver", "");
|
||||
this.updatePermissionField("approveTime", "");
|
||||
}
|
||||
}
|
||||
|
||||
this.updatePermissionField("state", value);
|
||||
})}>
|
||||
{
|
||||
[
|
||||
{id: "Approved", name: "Approved"},
|
||||
{id: "Pending", name: "Pending"},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
submitPermissionEdit(willExist) {
|
||||
if (this.state.permission.users.length === 0 && this.state.permission.roles.length === 0) {
|
||||
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.resources.length === 0) {
|
||||
Setting.showMessage("error", "The resources cannot be empty");
|
||||
return;
|
||||
}
|
||||
if (this.state.permission.actions.length === 0) {
|
||||
Setting.showMessage("error", "The actions cannot be empty");
|
||||
return;
|
||||
}
|
||||
if (!Setting.isLocalAdminUser(this.props.account) && this.state.permission.submitter !== this.props.account.name) {
|
||||
Setting.showMessage("error", "A normal user can only modify the permission submitted by itself");
|
||||
return;
|
||||
}
|
||||
|
||||
const permission = Setting.deepCopy(this.state.permission);
|
||||
PermissionBackend.updatePermission(this.state.organizationName, this.state.permissionName, permission)
|
||||
.then((res) => {
|
||||
|
@ -25,17 +25,22 @@ class PermissionListPage extends BaseListPage {
|
||||
newPermission() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: "built-in",
|
||||
owner: this.props.account.owner,
|
||||
name: `permission_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Permission - ${randomName}`,
|
||||
users: [],
|
||||
users: [this.props.account.name],
|
||||
roles: [],
|
||||
domains: [],
|
||||
resourceType: "Application",
|
||||
resources: ["app-built-in"],
|
||||
actions: ["Read"],
|
||||
effect: "Allow",
|
||||
isEnabled: true,
|
||||
submitter: this.props.account.name,
|
||||
approver: "",
|
||||
approveTime: "",
|
||||
state: "Pending",
|
||||
};
|
||||
}
|
||||
|
||||
@ -43,6 +48,10 @@ class PermissionListPage extends BaseListPage {
|
||||
const newPermission = this.newPermission();
|
||||
PermissionBackend.addPermission(newPermission)
|
||||
.then((res) => {
|
||||
if (res.msg !== "") {
|
||||
Setting.showMessage("error", res.msg);
|
||||
return;
|
||||
}
|
||||
this.props.history.push({pathname: `/permissions/${newPermission.owner}/${newPermission.name}`, mode: "add"});
|
||||
}
|
||||
)
|
||||
@ -139,6 +148,16 @@ class PermissionListPage extends BaseListPage {
|
||||
return Setting.getTags(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub domains"),
|
||||
dataIndex: "domains",
|
||||
key: "domains",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("domains"),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Resource type"),
|
||||
dataIndex: "resourceType",
|
||||
@ -196,6 +215,45 @@ class PermissionListPage extends BaseListPage {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Submitter"),
|
||||
dataIndex: "submitter",
|
||||
key: "submitter",
|
||||
filterMultiple: false,
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Approver"),
|
||||
dataIndex: "approver",
|
||||
key: "approver",
|
||||
filterMultiple: false,
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:Approve time"),
|
||||
dataIndex: "approveTime",
|
||||
key: "approveTime",
|
||||
filterMultiple: false,
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("permission:State"),
|
||||
dataIndex: "state",
|
||||
key: "state",
|
||||
filterMultiple: false,
|
||||
filters: [
|
||||
{text: "Approved", value: "Approved"},
|
||||
{text: "Pending", value: "Pending"},
|
||||
],
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: "",
|
||||
@ -249,7 +307,9 @@ class PermissionListPage extends BaseListPage {
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({loading: true});
|
||||
PermissionBackend.getPermissions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
|
||||
const getPermissions = Setting.isLocalAdminUser(this.props.account) ? PermissionBackend.getPermissions : PermissionBackend.getPermissionsBySubmitter;
|
||||
getPermissions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
|
@ -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"))} :
|
||||
|
@ -164,6 +164,20 @@ class RoleEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("role:Sub domains"), i18next.t("role:Sub domains - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: "100%"}} value={this.state.role.domains} onChange={(value => {
|
||||
this.updateRoleField("domains", value);
|
||||
})}>
|
||||
{
|
||||
this.state.role.domains.map((domain, index) => <Option key={index} value={domain}>{domain}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||
|
@ -31,6 +31,7 @@ class RoleListPage extends BaseListPage {
|
||||
displayName: `New Role - ${randomName}`,
|
||||
users: [],
|
||||
roles: [],
|
||||
domains: [],
|
||||
isEnabled: true,
|
||||
};
|
||||
}
|
||||
@ -135,6 +136,16 @@ class RoleListPage extends BaseListPage {
|
||||
return Setting.getTags(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("role:Sub domains"),
|
||||
dataIndex: "domains",
|
||||
key: "domains",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("domains"),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getTags(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Is enabled"),
|
||||
dataIndex: "isEnabled",
|
||||
|
@ -49,6 +49,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_huawei.png`,
|
||||
url: "https://www.huaweicloud.com/product/msgsms.html",
|
||||
},
|
||||
"Mock SMS": {
|
||||
logo: `${StaticBaseUrl}/img/social_default.png`,
|
||||
url: "",
|
||||
},
|
||||
},
|
||||
Email: {
|
||||
"Default": {
|
||||
@ -65,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",
|
||||
@ -373,6 +381,13 @@ export function isAdminUser(account) {
|
||||
return account.owner === "built-in" || account.isGlobalAdmin === true;
|
||||
}
|
||||
|
||||
export function isLocalAdminUser(account) {
|
||||
if (account === undefined || account === null) {
|
||||
return false;
|
||||
}
|
||||
return account.isAdmin === true || isAdminUser(account);
|
||||
}
|
||||
|
||||
export function deepCopy(obj) {
|
||||
return Object.assign({}, obj);
|
||||
}
|
||||
@ -532,7 +547,12 @@ export function getProviderLogoURL(provider) {
|
||||
}
|
||||
return `${StaticBaseUrl}/img/social_${provider.type.toLowerCase()}.png`;
|
||||
} else {
|
||||
return OtherProviderInfo[provider.category][provider.type].logo;
|
||||
const info = OtherProviderInfo[provider.category][provider.type];
|
||||
// avoid crash when provider is not found
|
||||
if (info) {
|
||||
return info.logo;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,6 +616,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"},
|
||||
|
111
web/src/SystemInfo.js
Normal file
111
web/src/SystemInfo.js
Normal file
@ -0,0 +1,111 @@
|
||||
// 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} 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: "v1.0.0",
|
||||
intervalId: null,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
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,
|
||||
});
|
||||
});
|
||||
}, 1000 * 3);
|
||||
this.setState({intervalId: id});
|
||||
}).catch(error => {
|
||||
Setting.showMessage("error", `System info failed to get: ${error}`);
|
||||
});
|
||||
|
||||
SystemBackend.getGitHubLatestReleaseVersion().then(res => {
|
||||
this.setState({latestVersion: res});
|
||||
}).catch(err => {
|
||||
Setting.showMessage("error", `get latest commit version failed: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.state.intervalId);
|
||||
}
|
||||
|
||||
render() {
|
||||
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.cpuUsage.length !== 0 &&
|
||||
this.state.cpuUsage.map((usage, i) => {
|
||||
return (
|
||||
<Progress key={i} percent={Number(usage.toFixed(1))} />
|
||||
);
|
||||
})
|
||||
}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card title={i18next.t("system:Memory Usage")} bordered={true} style={{textAlign: "center"}}>
|
||||
{(Number(this.state.memUsed) / 1024 / 1024).toFixed(2)} MB / {(Number(this.state.memTotal) / 1024 / 1024 / 1024).toFixed(2)} GB
|
||||
<br /> <br />
|
||||
<Progress type="circle" percent={Number((Number(this.state.memUsed) / Number(this.state.memTotal) * 100).toFixed(2))} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Divider />
|
||||
<Card title="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={`https://github.com/casdoor/casdoor/commit/${this.state.latestVersion}`}>{this.state.latestVersion.substring(0, 8)}</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;
|
@ -179,7 +179,7 @@ class LoginPage extends React.Component {
|
||||
values["type"] = "saml";
|
||||
}
|
||||
|
||||
if (this.state.owner !== null) {
|
||||
if (this.state.owner !== null && this.state.owner !== undefined) {
|
||||
values["organization"] = this.state.owner;
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,12 @@ export function getProviderUrl(provider) {
|
||||
|
||||
return `${urlObj.protocol}//${host}`;
|
||||
} else {
|
||||
return Setting.OtherProviderInfo[provider.category][provider.type].url;
|
||||
const info = Setting.OtherProviderInfo[provider.category][provider.type];
|
||||
// avoid crash when provider is not found
|
||||
if (info) {
|
||||
return info.url;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,13 @@ export function getPermissions(owner, page = "", pageSize = "", field = "", valu
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getPermissionsBySubmitter() {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-permissions-by-submitter`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getPermission(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-permission?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
|
29
web/src/backend/SystemInfo.js
Normal file
29
web/src/backend/SystemInfo.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
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());
|
||||
}
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "Aktion",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "Neu",
|
||||
"Affiliation URL": "Affiliation-URL",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
"SysInfo": "SysInfo",
|
||||
"Timestamp": "Zeitstempel",
|
||||
"Tokens": "Token",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "Aktionen",
|
||||
"Actions - Tooltip": "Aktionen - Tooltip",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "Berechtigung bearbeiten",
|
||||
"Effect": "Effekt",
|
||||
"Effect - Tooltip": "Effekt - Tooltip",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "Ressourcentyp",
|
||||
"Resource type - Tooltip": "Ressourcentyp - Tooltip",
|
||||
"Resources": "Ressourcen",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "Rolle bearbeiten",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "Unterrollen",
|
||||
"Sub roles - Tooltip": "Unterrollen - Tooltip",
|
||||
"Sub users": "Unternutzer",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "Primärschlüssel der Tabelle",
|
||||
"Table primary key - Tooltip": "Primärschlüssel der Tabelle - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Zugangs-Token",
|
||||
"Authorization code": "Autorisierungscode",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Affiliation URL - Tooltip": "Affiliation URL - Tooltip",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
"SysInfo": "SysInfo",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "Ajouter",
|
||||
"Affiliation URL": "URL d'affiliation",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Synchronisateurs",
|
||||
"SysInfo": "SysInfo",
|
||||
"Timestamp": "Horodatage",
|
||||
"Tokens": "Jetons",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Info-bulle",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "Autorisation d'édition",
|
||||
"Effect": "Effet",
|
||||
"Effect - Tooltip": "Effet - Infobulle",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "Type de ressource",
|
||||
"Resource type - Tooltip": "Type de ressource - infobulle",
|
||||
"Resources": "Ressource",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "Modifier le rôle",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "Sous-rôles",
|
||||
"Sub roles - Tooltip": "Sous-rôles - infobulle",
|
||||
"Sub users": "Sous-utilisateurs",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "Clé primaire de la table",
|
||||
"Table primary key - Tooltip": "Clé primaire du tableau - infobulle"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Jeton d'accès",
|
||||
"Authorization code": "Code d'autorisation",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "アクション",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "追加",
|
||||
"Affiliation URL": "アフィリエイトURL",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
"SysInfo": "システム情報",
|
||||
"Timestamp": "タイムスタンプ",
|
||||
"Tokens": "トークン",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "アクション",
|
||||
"Actions - Tooltip": "アクション → ツールチップ",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "権限を編集",
|
||||
"Effect": "効果",
|
||||
"Effect - Tooltip": "エフェクト - ツールチップ",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "リソースタイプ",
|
||||
"Resource type - Tooltip": "リソースタイプ - ツールチップ",
|
||||
"Resources": "リソース",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "役割を編集",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "サブロール",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "サブユーザー",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "テーブルのプライマリキー",
|
||||
"Table primary key - Tooltip": "テーブルのプライマリキー - ツールチップ"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "アクセストークン",
|
||||
"Authorization code": "認証コード",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "Action",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "Add",
|
||||
"Affiliation URL": "Affiliation URL",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Syncers",
|
||||
"SysInfo": "SysInfo",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "Actions",
|
||||
"Actions - Tooltip": "Actions - Tooltip",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "Edit Permission",
|
||||
"Effect": "Effect",
|
||||
"Effect - Tooltip": "Effect - Tooltip",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "Resource type",
|
||||
"Resource type - Tooltip": "Resource type - Tooltip",
|
||||
"Resources": "Resources",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "Edit Role",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "Sub roles",
|
||||
"Sub roles - Tooltip": "Sub roles - Tooltip",
|
||||
"Sub users": "Sub users",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "Table primary key",
|
||||
"Table primary key - Tooltip": "Table primary key - Tooltip"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Access token",
|
||||
"Authorization code": "Authorization code",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "Действие",
|
||||
"Adapter": "Adapter",
|
||||
"Adapter - Tooltip": "Adapter - Tooltip",
|
||||
"Add": "Добавить",
|
||||
"Affiliation URL": "URL-адрес партнёра",
|
||||
"Affiliation URL - Tooltip": "Unique string-style identifier",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "Swagger",
|
||||
"Sync": "Sync",
|
||||
"Syncers": "Синхронизаторы",
|
||||
"SysInfo": "Информация о системе",
|
||||
"Timestamp": "Отметка времени",
|
||||
"Tokens": "Жетоны",
|
||||
"URL": "URL",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "Действия",
|
||||
"Actions - Tooltip": "Действия - Подсказка",
|
||||
"Approve time": "Approve time",
|
||||
"Approve time - Tooltip": "Approve time - Tooltip",
|
||||
"Approver": "Approver",
|
||||
"Approver - Tooltip": "Approver - Tooltip",
|
||||
"Edit Permission": "Изменить права доступа",
|
||||
"Effect": "Эффект",
|
||||
"Effect - Tooltip": "Эффект - Подсказка",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "Тип ресурса",
|
||||
"Resource type - Tooltip": "Тип ресурса - Подсказка",
|
||||
"Resources": "Ресурсы",
|
||||
"Resources - Tooltip": "Resources - Tooltip"
|
||||
"Resources - Tooltip": "Resources - Tooltip",
|
||||
"State": "State",
|
||||
"State - Tooltip": "State - Tooltip",
|
||||
"Submitter": "Submitter",
|
||||
"Submitter - Tooltip": "Submitter - Tooltip"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "Alipay",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "Изменить роль",
|
||||
"New Role": "New Role",
|
||||
"Sub domains": "Sub domains",
|
||||
"Sub domains - Tooltip": "Sub domains - Tooltip",
|
||||
"Sub roles": "Суб роли",
|
||||
"Sub roles - Tooltip": "Суб роли - Tooltip",
|
||||
"Sub users": "Субпользователи",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "Основной ключ таблицы",
|
||||
"Table primary key - Tooltip": "Основная таблица - Подсказка"
|
||||
},
|
||||
"system": {
|
||||
"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",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Official Website": "Official Website",
|
||||
"Version": "Version"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "Маркер доступа",
|
||||
"Authorization code": "Код авторизации",
|
||||
|
@ -98,6 +98,8 @@
|
||||
},
|
||||
"general": {
|
||||
"Action": "操作",
|
||||
"Adapter": "适配器",
|
||||
"Adapter - Tooltip": "策略存储的表名",
|
||||
"Add": "添加",
|
||||
"Affiliation URL": "工作单位URL",
|
||||
"Affiliation URL - Tooltip": "工作单位URL",
|
||||
@ -196,6 +198,7 @@
|
||||
"Swagger": "API文档",
|
||||
"Sync": "同步",
|
||||
"Syncers": "同步器",
|
||||
"SysInfo": "系统信息",
|
||||
"Timestamp": "时间戳",
|
||||
"Tokens": "令牌",
|
||||
"URL": "链接",
|
||||
@ -343,6 +346,10 @@
|
||||
"permission": {
|
||||
"Actions": "动作",
|
||||
"Actions - Tooltip": "授权的动作",
|
||||
"Approve time": "审批时间",
|
||||
"Approve time - Tooltip": "该授权被审批通过的时间",
|
||||
"Approver": "审批者",
|
||||
"Approver - Tooltip": "审批通过该授权的人",
|
||||
"Edit Permission": "编辑权限",
|
||||
"Effect": "效果",
|
||||
"Effect - Tooltip": "允许还是拒绝",
|
||||
@ -350,7 +357,11 @@
|
||||
"Resource type": "资源类型",
|
||||
"Resource type - Tooltip": "授权资源的类型",
|
||||
"Resources": "资源",
|
||||
"Resources - Tooltip": "被授权的资源"
|
||||
"Resources - Tooltip": "被授权的资源",
|
||||
"State": "审批状态",
|
||||
"State - Tooltip": "该授权现在的状态",
|
||||
"Submitter": "申请者",
|
||||
"Submitter - Tooltip": "申请该授权的人"
|
||||
},
|
||||
"product": {
|
||||
"Alipay": "支付宝",
|
||||
@ -519,6 +530,8 @@
|
||||
"role": {
|
||||
"Edit Role": "编辑角色",
|
||||
"New Role": "添加角色",
|
||||
"Sub domains": "包含域",
|
||||
"Sub domains - Tooltip": "当前角色所包含的子域",
|
||||
"Sub roles": "包含角色",
|
||||
"Sub roles - Tooltip": "当前角色所包含的子角色",
|
||||
"Sub users": "包含用户",
|
||||
@ -581,6 +594,14 @@
|
||||
"Table primary key": "表主键",
|
||||
"Table primary key - Tooltip": "表主键,如id"
|
||||
},
|
||||
"system": {
|
||||
"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 Usage",
|
||||
"Community": "社区",
|
||||
"Memory Usage": "内存使用率",
|
||||
"Official Website": "官方网站",
|
||||
"Version": "版本"
|
||||
},
|
||||
"token": {
|
||||
"Access token": "访问令牌",
|
||||
"Authorization code": "授权码",
|
||||
|
Reference in New Issue
Block a user