mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-23 14:33:28 +08:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
1a9d02be46 | |||
eafaa135b4 | |||
6746551447 | |||
3cb46c3628 | |||
558bcf95d6 | |||
bb937c30c1 | |||
8dfdf7f767 | |||
62b2082e82 | |||
a1806439f8 | |||
01e58158b7 | |||
15427ad9d6 | |||
d058f78dc6 | |||
fd9dbf8251 | |||
3220a04fa9 | |||
f06a4990bd | |||
9df7de5f27 | |||
56c808c091 | |||
9fd2421564 | |||
689d45c7fa | |||
c24343bd53 | |||
979f43638d | |||
685a4514cd | |||
a05ca3af24 | |||
c6f301ff9e | |||
d7b2bcf288 | |||
67ac3d6d21 |
@ -90,7 +90,7 @@ func (c *ApiController) GetUsers() {
|
|||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
if groupName != "" {
|
if groupName != "" {
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(groupName))
|
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@ -567,6 +567,22 @@ func (c *ApiController) RemoveUserFromGroup() {
|
|||||||
name := c.Ctx.Request.Form.Get("name")
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
groupName := c.Ctx.Request.Form.Get("groupName")
|
groupName := c.Ctx.Request.Form.Get("groupName")
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.RemoveUserFromGroup(owner, name, groupName))
|
organization, err := object.GetOrganization(util.GetId("admin", owner))
|
||||||
c.ServeJSON()
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item := object.GetAccountItemByName("Groups", organization)
|
||||||
|
res, msg := object.CheckAccountItemModifyRule(item, c.IsAdmin(), c.GetAcceptLanguage())
|
||||||
|
if !res {
|
||||||
|
c.ResponseError(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := object.DeleteGroupForUser(util.GetId(owner, name), groupName)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(affected)
|
||||||
}
|
}
|
||||||
|
20
go.mod
20
go.mod
@ -12,9 +12,9 @@ require (
|
|||||||
github.com/beevik/etree v1.1.0
|
github.com/beevik/etree v1.1.0
|
||||||
github.com/casbin/casbin v1.9.1 // indirect
|
github.com/casbin/casbin v1.9.1 // indirect
|
||||||
github.com/casbin/casbin/v2 v2.30.1
|
github.com/casbin/casbin/v2 v2.30.1
|
||||||
github.com/casdoor/go-sms-sender v0.6.1
|
github.com/casdoor/go-sms-sender v0.12.0
|
||||||
github.com/casdoor/gomail/v2 v2.0.1
|
github.com/casdoor/gomail/v2 v2.0.1
|
||||||
github.com/casdoor/oss v1.2.1
|
github.com/casdoor/oss v1.3.0
|
||||||
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/denisenkom/go-mssqldb v0.9.0
|
github.com/denisenkom/go-mssqldb v0.9.0
|
||||||
@ -28,9 +28,6 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/go-webauthn/webauthn v0.6.0
|
github.com/go-webauthn/webauthn v0.6.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/mux v1.7.3 // indirect
|
github.com/gorilla/mux v1.7.3 // indirect
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||||
@ -43,7 +40,7 @@ require (
|
|||||||
github.com/nyaruka/phonenumbers v1.1.5
|
github.com/nyaruka/phonenumbers v1.1.5
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.11.1
|
github.com/prometheus/client_golang v1.11.1
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.3.0
|
||||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/russellhaering/gosaml2 v0.9.0
|
github.com/russellhaering/gosaml2 v0.9.0
|
||||||
@ -53,7 +50,7 @@ require (
|
|||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.3
|
||||||
github.com/tealeg/xlsx v1.0.5
|
github.com/tealeg/xlsx v1.0.5
|
||||||
github.com/thanhpk/randstr v1.0.4
|
github.com/thanhpk/randstr v1.0.4
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
@ -61,12 +58,11 @@ require (
|
|||||||
github.com/xorm-io/core v0.7.4
|
github.com/xorm-io/core v0.7.4
|
||||||
github.com/xorm-io/xorm v1.1.6
|
github.com/xorm-io/xorm v1.1.6
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.6.0
|
golang.org/x/crypto v0.11.0
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
golang.org/x/net v0.13.0
|
||||||
golang.org/x/net v0.7.0
|
golang.org/x/oauth2 v0.10.0
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
modernc.org/sqlite v1.18.2
|
||||||
)
|
)
|
||||||
|
@ -132,7 +132,7 @@ func (idp *GiteeIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
"type": "User",
|
"type": "User",
|
||||||
"blog": null,
|
"blog": null,
|
||||||
"weibo": null,
|
"weibo": null,
|
||||||
"bio": "个人博客:https://gitee.com/xxx/xxx/pages",
|
"bio": "bio",
|
||||||
"public_repos": 2,
|
"public_repos": 2,
|
||||||
"public_gists": 0,
|
"public_gists": 0,
|
||||||
"followers": 0,
|
"followers": 0,
|
||||||
|
1
main.go
1
main.go
@ -49,6 +49,7 @@ func main() {
|
|||||||
object.InitLdapAutoSynchronizer()
|
object.InitLdapAutoSynchronizer()
|
||||||
proxy.InitHttpClient()
|
proxy.InitHttpClient()
|
||||||
authz.InitApi()
|
authz.InitApi()
|
||||||
|
object.InitUserManager()
|
||||||
|
|
||||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
|
"github.com/xorm-io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Adapter struct {
|
type Adapter struct {
|
||||||
@ -33,7 +34,7 @@ type Adapter struct {
|
|||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
||||||
Host string `xorm:"varchar(100)" json:"host"`
|
Host string `xorm:"varchar(100)" json:"host"`
|
||||||
Port string `xorm:"varchar(20)" json:"port"`
|
Port int `json:"port"`
|
||||||
User string `xorm:"varchar(100)" json:"user"`
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
Password string `xorm:"varchar(100)" json:"password"`
|
Password string `xorm:"varchar(100)" json:"password"`
|
||||||
Database string `xorm:"varchar(100)" json:"database"`
|
Database string `xorm:"varchar(100)" json:"database"`
|
||||||
@ -153,21 +154,24 @@ func (adapter *Adapter) initAdapter() error {
|
|||||||
if adapter.Adapter == nil {
|
if adapter.Adapter == nil {
|
||||||
var dataSourceName string
|
var dataSourceName string
|
||||||
|
|
||||||
if adapter.buildInAdapter() {
|
if adapter.builtInAdapter() {
|
||||||
dataSourceName = conf.GetConfigString("dataSourceName")
|
dataSourceName = conf.GetConfigString("dataSourceName")
|
||||||
|
if adapter.DatabaseType == "mysql" {
|
||||||
|
dataSourceName = dataSourceName + adapter.Database
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch adapter.DatabaseType {
|
switch adapter.DatabaseType {
|
||||||
case "mssql":
|
case "mssql":
|
||||||
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s", adapter.User,
|
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "mysql":
|
case "mysql":
|
||||||
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%s)/", adapter.User,
|
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "postgres":
|
case "postgres":
|
||||||
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%s sslmode=disable dbname=%s", adapter.User,
|
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "CockroachDB":
|
case "CockroachDB":
|
||||||
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%s sslmode=disable dbname=%s serial_normalization=virtual_sequence",
|
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s serial_normalization=virtual_sequence",
|
||||||
adapter.User, adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
adapter.User, adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "sqlite3":
|
case "sqlite3":
|
||||||
dataSourceName = fmt.Sprintf("file:%s", adapter.Host)
|
dataSourceName = fmt.Sprintf("file:%s", adapter.Host)
|
||||||
@ -181,7 +185,8 @@ func (adapter *Adapter) initAdapter() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(adapter.DatabaseType, dataSourceName, adapter.Database).Engine, adapter.getTable(), adapter.TableNamePrefix)
|
engine, err := xorm.NewEngine(adapter.DatabaseType, dataSourceName)
|
||||||
|
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(engine, adapter.getTable(), adapter.TableNamePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -269,6 +274,11 @@ func UpdatePolicy(oldPolicy, newPolicy []string, adapter *Adapter) (bool, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return affected, err
|
return affected, err
|
||||||
}
|
}
|
||||||
|
err = adapter.SavePolicy(casbinModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return affected, nil
|
return affected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +295,10 @@ func AddPolicy(policy []string, adapter *Adapter) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
casbinModel.AddPolicy("p", "p", policy)
|
casbinModel.AddPolicy("p", "p", policy)
|
||||||
|
err = adapter.SavePolicy(casbinModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -305,15 +319,20 @@ func RemovePolicy(policy []string, adapter *Adapter) (bool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return affected, err
|
return affected, err
|
||||||
}
|
}
|
||||||
|
err = adapter.SavePolicy(casbinModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return affected, nil
|
return affected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Adapter) buildInAdapter() bool {
|
func (adapter *Adapter) builtInAdapter() bool {
|
||||||
if adapter.Owner != "built-in" {
|
if adapter.Owner != "built-in" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapter.Name == "permission-adapter-built-in" || adapter.Name == "api-adapter-built-in"
|
return adapter.Name == "user-adapter-built-in" || adapter.Name == "api-adapter-built-in"
|
||||||
}
|
}
|
||||||
|
|
||||||
func getModelDef() model.Model {
|
func getModelDef() model.Model {
|
||||||
|
@ -162,7 +162,7 @@ func UpdateCert(id string, cert *Cert) (bool, error) {
|
|||||||
if name != cert.Name {
|
if name != cert.Name {
|
||||||
err := certChangeTrigger(name, cert.Name)
|
err := certChangeTrigger(name, cert.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(cert)
|
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(cert)
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
|
|
||||||
"github.com/casbin/casbin/v2"
|
"github.com/casbin/casbin/v2"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@ -120,45 +120,50 @@ func DeleteEnforcer(enforcer *Enforcer) (bool, error) {
|
|||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Enforcer) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
||||||
|
}
|
||||||
|
|
||||||
func (enforcer *Enforcer) InitEnforcer() error {
|
func (enforcer *Enforcer) InitEnforcer() error {
|
||||||
if enforcer.Enforcer == nil {
|
if enforcer.Enforcer != nil {
|
||||||
if enforcer == nil {
|
return nil
|
||||||
return errors.New("enforcer is nil")
|
|
||||||
}
|
|
||||||
if enforcer.Model == "" || enforcer.Adapter == "" {
|
|
||||||
return errors.New("missing model or adapter")
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var m *Model
|
|
||||||
var a *Adapter
|
|
||||||
|
|
||||||
if m, err = GetModel(enforcer.Model); err != nil {
|
|
||||||
return err
|
|
||||||
} else if m == nil {
|
|
||||||
return errors.New("model not found")
|
|
||||||
}
|
|
||||||
if a, err = GetAdapter(enforcer.Adapter); err != nil {
|
|
||||||
return err
|
|
||||||
} else if a == nil {
|
|
||||||
return errors.New("adapter not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = m.initModel()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = a.initAdapter()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinEnforcer, err := casbin.NewEnforcer(m.Model, a.Adapter)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
enforcer.Enforcer = casbinEnforcer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if enforcer.Model == "" {
|
||||||
|
return fmt.Errorf("the model for enforcer: %s should not be empty", enforcer.GetId())
|
||||||
|
}
|
||||||
|
if enforcer.Adapter == "" {
|
||||||
|
return fmt.Errorf("the adapter for enforcer: %s should not be empty", enforcer.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := GetModel(enforcer.Model)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if m == nil {
|
||||||
|
return fmt.Errorf("the model: %s for enforcer: %s is not found", enforcer.Model, enforcer.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := GetAdapter(enforcer.Adapter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if a == nil {
|
||||||
|
return fmt.Errorf("the adapter: %s for enforcer: %s is not found", enforcer.Adapter, enforcer.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.initModel()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = a.initAdapter()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
casbinEnforcer, err := casbin.NewEnforcer(m.Model, a.Adapter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enforcer.Enforcer = casbinEnforcer
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ func DeleteGroup(group *Group) (bool, error) {
|
|||||||
return false, errors.New("group has children group")
|
return false, errors.New("group has children group")
|
||||||
}
|
}
|
||||||
|
|
||||||
if count, err := GetGroupUserCount(group.Name, "", ""); err != nil {
|
if count, err := GetGroupUserCount(group.GetId(), "", ""); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if count > 0 {
|
} else if count > 0 {
|
||||||
return false, errors.New("group has users")
|
return false, errors.New("group has users")
|
||||||
@ -214,39 +214,33 @@ func ConvertToTreeData(groups []*Group, parentId string) []*Group {
|
|||||||
return treeData
|
return treeData
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveUserFromGroup(owner, name, groupName string) (bool, error) {
|
func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
||||||
user, err := getUser(owner, name)
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return 0, err
|
||||||
}
|
|
||||||
if user == nil {
|
|
||||||
return false, errors.New("user not exist")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Groups = util.DeleteVal(user.Groups, groupName)
|
|
||||||
affected, err := updateUser(user.GetId(), user, []string{"groups"})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return affected != 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGroupUserCount(groupName string, field, value string) (int64, error) {
|
|
||||||
if field == "" && value == "" {
|
if field == "" && value == "" {
|
||||||
return ormer.Engine.Where(builder.Like{"`groups`", groupName}).
|
return int64(len(names)), nil
|
||||||
Count(&User{})
|
|
||||||
} else {
|
} else {
|
||||||
return ormer.Engine.Table("user").
|
return ormer.Engine.Table("user").
|
||||||
Where(builder.Like{"`groups`", groupName}).
|
Where("owner = ?", owner).In("name", names).
|
||||||
And(fmt.Sprintf("user.%s LIKE ?", util.CamelToSnakeCase(field)), "%"+value+"%").
|
And(fmt.Sprintf("user.%s LIKE ?", util.CamelToSnakeCase(field)), "%"+value+"%").
|
||||||
Count()
|
Count()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationGroupUsers(groupName string, offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
|
func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
|
||||||
users := []*User{}
|
users := []*User{}
|
||||||
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
session := ormer.Engine.Table("user").
|
session := ormer.Engine.Table("user").
|
||||||
Where(builder.Like{"`groups`", groupName + "\""})
|
Where("owner = ?", owner).In("name", names)
|
||||||
|
|
||||||
if offset != -1 && limit != -1 {
|
if offset != -1 && limit != -1 {
|
||||||
session.Limit(limit, offset)
|
session.Limit(limit, offset)
|
||||||
@ -265,7 +259,7 @@ func GetPaginationGroupUsers(groupName string, offset, limit int, field, value,
|
|||||||
session = session.Desc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
session = session.Desc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := session.Find(&users)
|
err = session.Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -273,15 +267,15 @@ func GetPaginationGroupUsers(groupName string, offset, limit int, field, value,
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupUsers(groupName string) ([]*User, error) {
|
func GetGroupUsers(groupId string) ([]*User, error) {
|
||||||
users := []*User{}
|
users := []*User{}
|
||||||
err := ormer.Engine.Table("user").
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
Where(builder.Like{"`groups`", groupName + "\""}).
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
Find(&users)
|
|
||||||
|
err = ormer.Engine.Where("owner = ?", owner).In("name", names).Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ func InitDb() {
|
|||||||
|
|
||||||
existed = initBuiltInApiModel()
|
existed = initBuiltInApiModel()
|
||||||
if !existed {
|
if !existed {
|
||||||
initBuildInApiAdapter()
|
initBuiltInApiAdapter()
|
||||||
initBuiltInApiEnforcer()
|
initBuiltInApiEnforcer()
|
||||||
initBuiltInPermissionModel()
|
initBuiltInUserModel()
|
||||||
initBuildInPermissionAdapter()
|
initBuiltInUserAdapter()
|
||||||
initBuiltInPermissionEnforcer()
|
initBuiltInUserEnforcer()
|
||||||
}
|
}
|
||||||
|
|
||||||
initWebAuthn()
|
initWebAuthn()
|
||||||
@ -303,8 +303,8 @@ func initWebAuthn() {
|
|||||||
gob.Register(webauthn.SessionData{})
|
gob.Register(webauthn.SessionData{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuiltInPermissionModel() {
|
func initBuiltInUserModel() {
|
||||||
model, err := GetModel("built-in/permission-model-built-in")
|
model, err := GetModel("built-in/user-model-built-in")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -315,7 +315,7 @@ func initBuiltInPermissionModel() {
|
|||||||
|
|
||||||
model = &Model{
|
model = &Model{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "permission-model-built-in",
|
Name: "user-model-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Built-in Model",
|
DisplayName: "Built-in Model",
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
@ -325,11 +325,14 @@ r = sub, obj, act
|
|||||||
[policy_definition]
|
[policy_definition]
|
||||||
p = sub, obj, act
|
p = sub, obj, act
|
||||||
|
|
||||||
|
[role_definition]
|
||||||
|
g = _, _
|
||||||
|
|
||||||
[policy_effect]
|
[policy_effect]
|
||||||
e = some(where (p.eft == allow))
|
e = some(where (p.eft == allow))
|
||||||
|
|
||||||
[matchers]
|
[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`,
|
||||||
}
|
}
|
||||||
_, err = AddModel(model)
|
_, err = AddModel(model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -347,8 +350,7 @@ func initBuiltInApiModel() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
modelText := `
|
modelText := `[request_definition]
|
||||||
[request_definition]
|
|
||||||
r = subOwner, subName, method, urlPath, objOwner, objName
|
r = subOwner, subName, method, urlPath, objOwner, objName
|
||||||
|
|
||||||
[policy_definition]
|
[policy_definition]
|
||||||
@ -367,8 +369,7 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
|
|||||||
(r.urlPath == p.urlPath || p.urlPath == "*") && \
|
(r.urlPath == p.urlPath || p.urlPath == "*") && \
|
||||||
(r.objOwner == p.objOwner || p.objOwner == "*") && \
|
(r.objOwner == p.objOwner || p.objOwner == "*") && \
|
||||||
(r.objName == p.objName || p.objName == "*") || \
|
(r.objName == p.objName || p.objName == "*") || \
|
||||||
(r.subOwner == r.objOwner && r.subName == r.objName)
|
(r.subOwner == r.objOwner && r.subName == r.objName)`
|
||||||
`
|
|
||||||
|
|
||||||
model = &Model{
|
model = &Model{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
@ -415,19 +416,19 @@ func initBuiltInPermission() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuildInPermissionAdapter() {
|
func initBuiltInUserAdapter() {
|
||||||
permissionAdapter, err := GetAdapter("built-in/permission-adapter-built-in")
|
adapter, err := GetAdapter("built-in/user-adapter-built-in")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if permissionAdapter != nil {
|
if adapter != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionAdapter = &Adapter{
|
adapter = &Adapter{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "permission-adapter-built-in",
|
Name: "user-adapter-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
Type: "Database",
|
Type: "Database",
|
||||||
DatabaseType: conf.GetConfigString("driverName"),
|
DatabaseType: conf.GetConfigString("driverName"),
|
||||||
@ -436,23 +437,23 @@ func initBuildInPermissionAdapter() {
|
|||||||
Table: "casbin_user_rule",
|
Table: "casbin_user_rule",
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
_, err = AddAdapter(permissionAdapter)
|
_, err = AddAdapter(adapter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuildInApiAdapter() {
|
func initBuiltInApiAdapter() {
|
||||||
apiAdapter, err := GetAdapter("built-in/api-adapter-built-in")
|
adapter, err := GetAdapter("built-in/api-adapter-built-in")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiAdapter != nil {
|
if adapter != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiAdapter = &Adapter{
|
adapter = &Adapter{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "api-adapter-built-in",
|
Name: "api-adapter-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
@ -463,49 +464,49 @@ func initBuildInApiAdapter() {
|
|||||||
Table: "casbin_api_rule",
|
Table: "casbin_api_rule",
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
_, err = AddAdapter(apiAdapter)
|
_, err = AddAdapter(adapter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuiltInPermissionEnforcer() {
|
func initBuiltInUserEnforcer() {
|
||||||
permissionEnforcer, err := GetEnforcer("built-in/permission-enforcer-built-in")
|
enforcer, err := GetEnforcer("built-in/user-enforcer-built-in")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if permissionEnforcer != nil {
|
if enforcer != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionEnforcer = &Enforcer{
|
enforcer = &Enforcer{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "permission-enforcer-built-in",
|
Name: "user-enforcer-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Permission Enforcer",
|
DisplayName: "Permission Enforcer",
|
||||||
Model: "built-in/permission-model-built-in",
|
Model: "built-in/user-model-built-in",
|
||||||
Adapter: "built-in/permission-adapter-built-in",
|
Adapter: "built-in/user-adapter-built-in",
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = AddEnforcer(permissionEnforcer)
|
_, err = AddEnforcer(enforcer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuiltInApiEnforcer() {
|
func initBuiltInApiEnforcer() {
|
||||||
apiEnforcer, err := GetEnforcer("built-in/api-enforcer-built-in")
|
enforcer, err := GetEnforcer("built-in/api-enforcer-built-in")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiEnforcer != nil {
|
if enforcer != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiEnforcer = &Enforcer{
|
enforcer = &Enforcer{
|
||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "api-enforcer-built-in",
|
Name: "api-enforcer-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
@ -515,7 +516,7 @@ func initBuiltInApiEnforcer() {
|
|||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = AddEnforcer(apiEnforcer)
|
_, err = AddEnforcer(enforcer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ type LdapUser struct {
|
|||||||
GidNumber string `json:"gidNumber"`
|
GidNumber string `json:"gidNumber"`
|
||||||
// Gcn string
|
// Gcn string
|
||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
|
UserPrincipalName string `json:"userPrincipalName"`
|
||||||
DisplayName string `json:"displayName"`
|
DisplayName string `json:"displayName"`
|
||||||
Mail string
|
Mail string
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
@ -51,9 +52,10 @@ type LdapUser struct {
|
|||||||
RegisteredAddress string
|
RegisteredAddress string
|
||||||
PostalAddress string
|
PostalAddress string
|
||||||
|
|
||||||
GroupId string `json:"groupId"`
|
GroupId string `json:"groupId"`
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
|
MemberOf string `json:"memberOf"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
||||||
@ -168,6 +170,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
|||||||
user.Uuid = attribute.Values[0]
|
user.Uuid = attribute.Values[0]
|
||||||
case "objectGUID":
|
case "objectGUID":
|
||||||
user.Uuid = attribute.Values[0]
|
user.Uuid = attribute.Values[0]
|
||||||
|
case "userPrincipalName":
|
||||||
|
user.UserPrincipalName = attribute.Values[0]
|
||||||
case "displayName":
|
case "displayName":
|
||||||
user.DisplayName = attribute.Values[0]
|
user.DisplayName = attribute.Values[0]
|
||||||
case "mail":
|
case "mail":
|
||||||
@ -186,6 +190,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
|||||||
user.RegisteredAddress = attribute.Values[0]
|
user.RegisteredAddress = attribute.Values[0]
|
||||||
case "postalAddress":
|
case "postalAddress":
|
||||||
user.PostalAddress = attribute.Values[0]
|
user.PostalAddress = attribute.Values[0]
|
||||||
|
case "memberOf":
|
||||||
|
user.MemberOf = attribute.Values[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ldapUsers = append(ldapUsers, user)
|
ldapUsers = append(ldapUsers, user)
|
||||||
|
@ -189,7 +189,7 @@ func UpdateOrganization(id string, organization *Organization) (bool, error) {
|
|||||||
if name != organization.Name {
|
if name != organization.Name {
|
||||||
err := organizationChangeTrigger(name, organization.Name)
|
err := organizationChangeTrigger(name, organization.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +432,7 @@ func organizationChangeTrigger(oldName string, newName string) error {
|
|||||||
|
|
||||||
payment := new(Payment)
|
payment := new(Payment)
|
||||||
payment.Owner = newName
|
payment.Owner = newName
|
||||||
_, err = session.Where("organization=?", oldName).Update(payment)
|
_, err = session.Where("owner=?", oldName).Update(payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -186,20 +186,23 @@ func notifyPayment(request *http.Request, body []byte, owner string, paymentName
|
|||||||
|
|
||||||
notifyResult, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId)
|
notifyResult, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return payment, notifyResult, err
|
return payment, nil, err
|
||||||
}
|
}
|
||||||
|
if notifyResult.PaymentStatus != pp.PaymentStatePaid {
|
||||||
|
return payment, notifyResult, nil
|
||||||
|
}
|
||||||
|
// Only check paid payment
|
||||||
if notifyResult.ProductDisplayName != "" && notifyResult.ProductDisplayName != product.DisplayName {
|
if notifyResult.ProductDisplayName != "" && notifyResult.ProductDisplayName != product.DisplayName {
|
||||||
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", notifyResult.ProductDisplayName, product.DisplayName)
|
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", notifyResult.ProductDisplayName, product.DisplayName)
|
||||||
return payment, notifyResult, err
|
return payment, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if notifyResult.Price != product.Price {
|
if notifyResult.Price != product.Price {
|
||||||
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", notifyResult.Price, product.Price)
|
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", notifyResult.Price, product.Price)
|
||||||
return payment, notifyResult, err
|
return payment, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return payment, notifyResult, err
|
return payment, notifyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, error) {
|
func NotifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, error) {
|
||||||
@ -210,6 +213,7 @@ func NotifyPayment(request *http.Request, body []byte, owner string, paymentName
|
|||||||
payment.Message = err.Error()
|
payment.Message = err.Error()
|
||||||
} else {
|
} else {
|
||||||
payment.State = notifyResult.PaymentStatus
|
payment.State = notifyResult.PaymentStatus
|
||||||
|
payment.Message = notifyResult.NotifyMessage
|
||||||
}
|
}
|
||||||
_, err = UpdatePayment(payment.GetId(), payment)
|
_, err = UpdatePayment(payment.GetId(), payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,10 +58,7 @@ type PermissionRule struct {
|
|||||||
Id string `xorm:"varchar(100) index not null default ''" json:"id"`
|
Id string `xorm:"varchar(100) index not null default ''" json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
|
||||||
builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
|
|
||||||
builtInAdapter = "permission_rule"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *Permission) GetId() string {
|
func (p *Permission) GetId() string {
|
||||||
return util.GetId(p.Owner, p.Name)
|
return util.GetId(p.Owner, p.Name)
|
||||||
@ -290,7 +287,7 @@ func GetPermissionsAndRolesByUser(userId string) ([]*Permission, []*Role, error)
|
|||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
perms := []*Permission{}
|
perms := []*Permission{}
|
||||||
err := ormer.Engine.Where("roles like ?", "%"+role.Name+"\"%").Find(&perms)
|
err := ormer.Engine.Where("roles like ?", "%"+role.GetId()+"\"%").Find(&perms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
|
|||||||
policyDefinition := strings.Split(cfg.String("policy_definition::p"), ",")
|
policyDefinition := strings.Split(cfg.String("policy_definition::p"), ",")
|
||||||
fieldsNum := len(policyDefinition)
|
fieldsNum := len(policyDefinition)
|
||||||
if fieldsNum > builtInAvailableField {
|
if fieldsNum > builtInAvailableField {
|
||||||
panic(fmt.Errorf("the maximum policy_definition field number cannot exceed %d", builtInAvailableField))
|
panic(fmt.Errorf("the maximum policy_definition field number cannot exceed %d, got %d", builtInAvailableField, fieldsNum))
|
||||||
}
|
}
|
||||||
// filled empty field with "" and V5 with "permissionId"
|
// filled empty field with "" and V5 with "permissionId"
|
||||||
for i := builtInAvailableField - fieldsNum; i > 0; i-- {
|
for i := builtInAvailableField - fieldsNum; i > 0; i-- {
|
||||||
|
@ -203,7 +203,7 @@ func UpdateProvider(id string, provider *Provider) (bool, error) {
|
|||||||
if name != provider.Name {
|
if name != provider.Name {
|
||||||
err := providerChangeTrigger(name, provider.Name)
|
err := providerChangeTrigger(name, provider.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +254,8 @@ func DeleteProvider(provider *Provider) (bool, error) {
|
|||||||
func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
||||||
cert := &Cert{}
|
cert := &Cert{}
|
||||||
if p.Cert != "" {
|
if p.Cert != "" {
|
||||||
cert, err := getCert(p.Owner, p.Cert)
|
var err error
|
||||||
|
cert, err = getCert(p.Owner, p.Cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ func UpdateRole(id string, role *Role) (bool, error) {
|
|||||||
if name != role.Name {
|
if name != role.Name {
|
||||||
err := roleChangeTrigger(name, role.Name)
|
err := roleChangeTrigger(name, role.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ func getSmsClient(provider *Provider) (sender.SmsClient, error) {
|
|||||||
var client sender.SmsClient
|
var client sender.SmsClient
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if provider.Type == sender.HuaweiCloud {
|
if provider.Type == sender.HuaweiCloud || provider.Type == sender.AzureACS {
|
||||||
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.ProviderUrl, provider.AppId)
|
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.ProviderUrl, provider.AppId)
|
||||||
} else {
|
} else {
|
||||||
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
|
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
|
||||||
|
@ -25,6 +25,7 @@ type TableColumn struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
CasdoorName string `json:"casdoorName"`
|
CasdoorName string `json:"casdoorName"`
|
||||||
|
IsKey bool `json:"isKey"`
|
||||||
IsHashed bool `json:"isHashed"`
|
IsHashed bool `json:"isHashed"`
|
||||||
Values []string `json:"values"`
|
Values []string `json:"values"`
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,23 @@ const (
|
|||||||
UserPropertiesWechatOpenId = "wechatOpenId"
|
UserPropertiesWechatOpenId = "wechatOpenId"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const UserEnforcerId = "built-in/user-enforcer-built-in"
|
||||||
|
|
||||||
|
var userEnforcer *UserGroupEnforcer
|
||||||
|
|
||||||
|
func InitUserManager() {
|
||||||
|
enforcer, err := GetEnforcer(UserEnforcerId)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = enforcer.InitEnforcer()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userEnforcer = NewUserGroupEnforcer(enforcer.Enforcer)
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
@ -230,7 +247,7 @@ func GetUserCount(owner, field, value string, groupName string) (int64, error) {
|
|||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
|
||||||
if groupName != "" {
|
if groupName != "" {
|
||||||
return GetGroupUserCount(groupName, field, value)
|
return GetGroupUserCount(util.GetId(owner, groupName), field, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return session.Count(&User{})
|
return session.Count(&User{})
|
||||||
@ -274,7 +291,7 @@ func GetPaginationUsers(owner string, offset, limit int, field, value, sortField
|
|||||||
users := []*User{}
|
users := []*User{}
|
||||||
|
|
||||||
if groupName != "" {
|
if groupName != "" {
|
||||||
return GetPaginationGroupUsers(groupName, offset, limit, field, value, sortField, sortOrder)
|
return GetPaginationGroupUsers(util.GetId(owner, groupName), offset, limit, field, value, sortField, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
session := GetSessionForUser(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSessionForUser(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
@ -531,6 +548,13 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
|||||||
columns = append(columns, "name", "email", "phone", "country_code")
|
columns = append(columns, "name", "email", "phone", "country_code")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if util.ContainsString(columns, "groups") {
|
||||||
|
_, err := userEnforcer.UpdateGroupsForUser(user.GetId(), user.Groups)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
affected, err := updateUser(id, user, columns)
|
affected, err := updateUser(id, user, columns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -568,7 +592,7 @@ func UpdateUserForAllFields(id string, user *User) (bool, error) {
|
|||||||
if name != user.Name {
|
if name != user.Name {
|
||||||
err := userChangeTrigger(name, user.Name)
|
err := userChangeTrigger(name, user.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,6 +802,10 @@ func ExtendUserWithRolesAndPermissions(user *User) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteGroupForUser(user string, group string) (bool, error) {
|
||||||
|
return userEnforcer.DeleteGroupForUser(user, group)
|
||||||
|
}
|
||||||
|
|
||||||
func userChangeTrigger(oldName string, newName string) error {
|
func userChangeTrigger(oldName string, newName string) error {
|
||||||
session := ormer.Engine.NewSession()
|
session := ormer.Engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
|
@ -69,6 +69,8 @@ func downloadImage(client *http.Client, url string) (*bytes.Buffer, string, erro
|
|||||||
fileExtension = ".ico"
|
fileExtension = ".ico"
|
||||||
case "image/x-icon":
|
case "image/x-icon":
|
||||||
fileExtension = ".ico"
|
fileExtension = ".ico"
|
||||||
|
case "image/svg+xml":
|
||||||
|
fileExtension = ".svg"
|
||||||
default:
|
default:
|
||||||
return nil, "", fmt.Errorf("unsupported content type: %s", contentType)
|
return nil, "", fmt.Errorf("unsupported content type: %s", contentType)
|
||||||
}
|
}
|
||||||
|
95
object/user_enforcer.go
Normal file
95
object/user_enforcer.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/casbin/casbin/v2/errors"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserGroupEnforcer struct {
|
||||||
|
// use rbac model implement use group, the enforcer can also implement user role
|
||||||
|
enforcer *casbin.Enforcer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserGroupEnforcer(enforcer *casbin.Enforcer) *UserGroupEnforcer {
|
||||||
|
return &UserGroupEnforcer{
|
||||||
|
enforcer: enforcer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) AddGroupForUser(user string, group string) (bool, error) {
|
||||||
|
return e.enforcer.AddRoleForUser(user, GetGroupWithPrefix(group))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) AddGroupsForUser(user string, groups []string) (bool, error) {
|
||||||
|
g := make([]string, len(groups))
|
||||||
|
for i, group := range groups {
|
||||||
|
g[i] = GetGroupWithPrefix(group)
|
||||||
|
}
|
||||||
|
return e.enforcer.AddRolesForUser(user, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) DeleteGroupForUser(user string, group string) (bool, error) {
|
||||||
|
return e.enforcer.DeleteRoleForUser(user, GetGroupWithPrefix(group))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) DeleteGroupsForUser(user string) (bool, error) {
|
||||||
|
return e.enforcer.DeleteRolesForUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetGroupsForUser(user string) ([]string, error) {
|
||||||
|
groups, err := e.enforcer.GetRolesForUser(user)
|
||||||
|
for i, group := range groups {
|
||||||
|
groups[i] = GetGroupWithoutPrefix(group)
|
||||||
|
}
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetAllUsersByGroup(group string) ([]string, error) {
|
||||||
|
users, err := e.enforcer.GetUsersForRole(GetGroupWithPrefix(group))
|
||||||
|
if err != nil {
|
||||||
|
if err == errors.ERR_NAME_NOT_FOUND {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupWithPrefix(group string) string {
|
||||||
|
return "group:" + group
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupWithoutPrefix(group string) string {
|
||||||
|
return group[len("group:"):]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetUserNamesByGroupName(groupName string) ([]string, error) {
|
||||||
|
var names []string
|
||||||
|
|
||||||
|
userIds, err := e.GetAllUsersByGroup(groupName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userId := range userIds {
|
||||||
|
_, name := util.GetOwnerAndNameFromIdNoCheck(userId)
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) UpdateGroupsForUser(user string, groups []string) (bool, error) {
|
||||||
|
_, err := e.DeleteGroupsForUser(user)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := e.AddGroupsForUser(user, groups)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected, nil
|
||||||
|
}
|
28
pp/paypal.go
28
pp/paypal.go
@ -17,6 +17,7 @@ package pp
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -89,14 +90,24 @@ func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
|
notifyResult := &NotifyResult{}
|
||||||
captureRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
|
captureRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if captureRsp.Code != paypal.Success {
|
if captureRsp.Code != paypal.Success {
|
||||||
|
errDetail := captureRsp.ErrorResponse.Details[0]
|
||||||
|
switch errDetail.Issue {
|
||||||
// If order is already captured, just skip this type of error and check the order detail
|
// If order is already captured, just skip this type of error and check the order detail
|
||||||
if !(len(captureRsp.ErrorResponse.Details) == 1 && captureRsp.ErrorResponse.Details[0].Issue == "ORDER_ALREADY_CAPTURED") {
|
case "ORDER_ALREADY_CAPTURED":
|
||||||
return nil, errors.New(captureRsp.ErrorResponse.Message)
|
// skip
|
||||||
|
case "ORDER_NOT_APPROVED":
|
||||||
|
notifyResult.PaymentStatus = PaymentStateCanceled
|
||||||
|
notifyResult.NotifyMessage = errDetail.Description
|
||||||
|
return notifyResult, nil
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf(errDetail.Description)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check the order detail
|
// Check the order detail
|
||||||
@ -105,7 +116,16 @@ func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if captureRsp.Code != paypal.Success {
|
if captureRsp.Code != paypal.Success {
|
||||||
return nil, errors.New(captureRsp.ErrorResponse.Message)
|
errDetail := captureRsp.ErrorResponse.Details[0]
|
||||||
|
switch errDetail.Issue {
|
||||||
|
case "ORDER_NOT_APPROVED":
|
||||||
|
notifyResult.PaymentStatus = PaymentStateCanceled
|
||||||
|
notifyResult.NotifyMessage = errDetail.Description
|
||||||
|
return notifyResult, nil
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf(errDetail.Description)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentName := detailRsp.Response.Id
|
paymentName := detailRsp.Response.Id
|
||||||
@ -126,7 +146,7 @@ func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
default:
|
default:
|
||||||
paymentStatus = PaymentStateError
|
paymentStatus = PaymentStateError
|
||||||
}
|
}
|
||||||
notifyResult := &NotifyResult{
|
notifyResult = &NotifyResult{
|
||||||
PaymentStatus: paymentStatus,
|
PaymentStatus: paymentStatus,
|
||||||
PaymentName: paymentName,
|
PaymentName: paymentName,
|
||||||
|
|
||||||
|
@ -21,16 +21,18 @@ import (
|
|||||||
type PaymentState string
|
type PaymentState string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PaymentStatePaid PaymentState = "Paid"
|
PaymentStatePaid PaymentState = "Paid"
|
||||||
PaymentStateCreated PaymentState = "Created"
|
PaymentStateCreated PaymentState = "Created"
|
||||||
PaymentStateError PaymentState = "Error"
|
PaymentStateCanceled PaymentState = "Canceled"
|
||||||
|
PaymentStateError PaymentState = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotifyResult struct {
|
type NotifyResult struct {
|
||||||
PaymentName string
|
PaymentName string
|
||||||
PaymentStatus PaymentState
|
PaymentStatus PaymentState
|
||||||
ProviderName string
|
NotifyMessage string
|
||||||
|
|
||||||
|
ProviderName string
|
||||||
ProductName string
|
ProductName string
|
||||||
ProductDisplayName string
|
ProductDisplayName string
|
||||||
Price float64
|
Price float64
|
||||||
|
@ -55,12 +55,6 @@ func StaticFilter(ctx *context.Context) {
|
|||||||
path += urlPath
|
path += urlPath
|
||||||
}
|
}
|
||||||
|
|
||||||
path2 := strings.TrimPrefix(path, "web/build/images/")
|
|
||||||
if util.FileExist(path2) {
|
|
||||||
makeGzipResponse(ctx.ResponseWriter, ctx.Request, path2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !util.FileExist(path) {
|
if !util.FileExist(path) {
|
||||||
path = "web/build/index.html"
|
path = "web/build/index.html"
|
||||||
}
|
}
|
||||||
|
31
storage/google_cloud.go
Normal file
31
storage/google_cloud.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casdoor/oss"
|
||||||
|
"github.com/casdoor/oss/googlecloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGoogleCloudStorageProvider(clientId string, clientSecret string, bucket string, endpoint string) oss.StorageInterface {
|
||||||
|
sp, _ := googlecloud.New(&googlecloud.Config{
|
||||||
|
AccessID: clientId,
|
||||||
|
AccessKey: clientSecret,
|
||||||
|
Bucket: bucket,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
})
|
||||||
|
|
||||||
|
return sp
|
||||||
|
}
|
32
storage/qiniu_cloud.go
Normal file
32
storage/qiniu_cloud.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casdoor/oss"
|
||||||
|
"github.com/casdoor/oss/qiniu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewQiniuCloudKodoStorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
|
||||||
|
sp := qiniu.New(&qiniu.Config{
|
||||||
|
AccessID: clientId,
|
||||||
|
AccessKey: clientSecret,
|
||||||
|
Region: region,
|
||||||
|
Bucket: bucket,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
})
|
||||||
|
|
||||||
|
return sp
|
||||||
|
}
|
@ -30,6 +30,10 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
|
|||||||
return NewTencentCloudCosStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewTencentCloudCosStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
case "Azure Blob":
|
case "Azure Blob":
|
||||||
return NewAzureBlobStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewAzureBlobStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
|
case "Qiniu Cloud Kodo":
|
||||||
|
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
|
case "Google Cloud Storage":
|
||||||
|
return NewGoogleCloudStorageProvider(clientId, clientSecret, bucket, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -25,5 +25,12 @@ func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
|
|||||||
casbinRule.V4,
|
casbinRule.V4,
|
||||||
casbinRule.V5,
|
casbinRule.V5,
|
||||||
}
|
}
|
||||||
|
// remove empty strings from end, for update model policy map
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
if s[i] != "" {
|
||||||
|
s = s[:i+1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/cssinjs": "^1.8.1",
|
"@ant-design/cssinjs": "1.16.1",
|
||||||
"@ant-design/icons": "^4.7.0",
|
"@ant-design/icons": "^4.7.0",
|
||||||
"@craco/craco": "^6.4.5",
|
"@craco/craco": "^6.4.5",
|
||||||
"@crowdin/cli": "^3.7.10",
|
"@crowdin/cli": "^3.7.10",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Card, Col, Input, Row, Select, Switch} from "antd";
|
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
||||||
import * as AdapterBackend from "./backend/AdapterBackend";
|
import * as AdapterBackend from "./backend/AdapterBackend";
|
||||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
@ -107,8 +107,8 @@ class AdapterEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.adapter.port} onChange={e => {
|
<InputNumber value={this.state.adapter.port} min={0} max={65535} onChange={value => {
|
||||||
this.updateAdapterField("port", e.target.value);
|
this.updateAdapterField("port", value);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -32,7 +32,7 @@ class AdapterListPage extends BaseListPage {
|
|||||||
createdTime: moment().format(),
|
createdTime: moment().format(),
|
||||||
type: "Database",
|
type: "Database",
|
||||||
host: "localhost",
|
host: "localhost",
|
||||||
port: "3306",
|
port: 3306,
|
||||||
user: "root",
|
user: "root",
|
||||||
password: "123456",
|
password: "123456",
|
||||||
databaseType: "mysql",
|
databaseType: "mysql",
|
||||||
|
203
web/src/App.js
203
web/src/App.js
@ -18,7 +18,7 @@ import {Helmet} from "react-helmet";
|
|||||||
import {MfaRuleRequired} from "./Setting";
|
import {MfaRuleRequired} from "./Setting";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
|
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
|
||||||
import {BarsOutlined, DownOutlined, InfoCircleFilled, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
|
import {AppstoreTwoTone, BarsOutlined, DollarTwoTone, DownOutlined, HomeTwoTone, InfoCircleFilled, LockTwoTone, LogoutOutlined, SafetyCertificateTwoTone, SettingOutlined, SettingTwoTone, WalletTwoTone} from "@ant-design/icons";
|
||||||
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd";
|
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd";
|
||||||
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
||||||
import OrganizationListPage from "./OrganizationListPage";
|
import OrganizationListPage from "./OrganizationListPage";
|
||||||
@ -91,6 +91,10 @@ import AccountAvatar from "./account/AccountAvatar";
|
|||||||
|
|
||||||
const {Header, Footer, Content} = Layout;
|
const {Header, Footer, Content} = Layout;
|
||||||
|
|
||||||
|
import {setTwoToneColor} from "@ant-design/icons";
|
||||||
|
|
||||||
|
setTwoToneColor("rgb(87,52,211)");
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -147,58 +151,24 @@ class App extends Component {
|
|||||||
});
|
});
|
||||||
if (uri === "/") {
|
if (uri === "/") {
|
||||||
this.setState({selectedMenuKey: "/"});
|
this.setState({selectedMenuKey: "/"});
|
||||||
} else if (uri.includes("/organizations") || uri.includes("/trees")) {
|
} else if (uri.includes("/organizations") || uri.includes("/trees") || uri.includes("/users") || uri.includes("/groups")) {
|
||||||
this.setState({selectedMenuKey: "/organizations"});
|
this.setState({selectedMenuKey: "/orgs"});
|
||||||
} else if (uri.includes("/users")) {
|
} else if (uri.includes("/roles") || uri.includes("/permissions") || uri.includes("/models") || uri.includes("/adapters") || uri.includes("/enforcers")) {
|
||||||
this.setState({selectedMenuKey: "/users"});
|
this.setState({selectedMenuKey: "/auth"});
|
||||||
} else if (uri.includes("/groups")) {
|
} else if (uri.includes("/applications") || uri.includes("/providers") || uri.includes("/resources") || uri.includes("/certs")) {
|
||||||
this.setState({selectedMenuKey: "/groups"});
|
this.setState({selectedMenuKey: "/identity"});
|
||||||
} else if (uri.includes("/roles")) {
|
} else if (uri.includes("/records") || uri.includes("/tokens") || uri.includes("/sessions")) {
|
||||||
this.setState({selectedMenuKey: "/roles"});
|
this.setState({selectedMenuKey: "/logs"});
|
||||||
} else if (uri.includes("/permissions")) {
|
} else if (uri.includes("/products") || uri.includes("/payments") || uri.includes("/plans") || uri.includes("/pricings") || uri.includes("/subscriptions")) {
|
||||||
this.setState({selectedMenuKey: "/permissions"});
|
this.setState({selectedMenuKey: "/business"});
|
||||||
} else if (uri.includes("/models")) {
|
} else if (uri.includes("/sysinfo") || uri.includes("/syncers") || uri.includes("/webhooks")) {
|
||||||
this.setState({selectedMenuKey: "/models"});
|
this.setState({selectedMenuKey: "/admin"});
|
||||||
} else if (uri.includes("/adapters")) {
|
|
||||||
this.setState({selectedMenuKey: "/adapters"});
|
|
||||||
} else if (uri.includes("/enforcers")) {
|
|
||||||
this.setState({selectedMenuKey: "/enforcers"});
|
|
||||||
} else if (uri.includes("/providers")) {
|
|
||||||
this.setState({selectedMenuKey: "/providers"});
|
|
||||||
} else if (uri.includes("/applications")) {
|
|
||||||
this.setState({selectedMenuKey: "/applications"});
|
|
||||||
} else if (uri.includes("/resources")) {
|
|
||||||
this.setState({selectedMenuKey: "/resources"});
|
|
||||||
} else if (uri.includes("/records")) {
|
|
||||||
this.setState({selectedMenuKey: "/records"});
|
|
||||||
} else if (uri.includes("/tokens")) {
|
|
||||||
this.setState({selectedMenuKey: "/tokens"});
|
|
||||||
} else if (uri.includes("/sessions")) {
|
|
||||||
this.setState({selectedMenuKey: "/sessions"});
|
|
||||||
} else if (uri.includes("/webhooks")) {
|
|
||||||
this.setState({selectedMenuKey: "/webhooks"});
|
|
||||||
} else if (uri.includes("/syncers")) {
|
|
||||||
this.setState({selectedMenuKey: "/syncers"});
|
|
||||||
} else if (uri.includes("/certs")) {
|
|
||||||
this.setState({selectedMenuKey: "/certs"});
|
|
||||||
} else if (uri.includes("/products")) {
|
|
||||||
this.setState({selectedMenuKey: "/products"});
|
|
||||||
} else if (uri.includes("/payments")) {
|
|
||||||
this.setState({selectedMenuKey: "/payments"});
|
|
||||||
} else if (uri.includes("/signup")) {
|
} else if (uri.includes("/signup")) {
|
||||||
this.setState({selectedMenuKey: "/signup"});
|
this.setState({selectedMenuKey: "/signup"});
|
||||||
} else if (uri.includes("/login")) {
|
} else if (uri.includes("/login")) {
|
||||||
this.setState({selectedMenuKey: "/login"});
|
this.setState({selectedMenuKey: "/login"});
|
||||||
} else if (uri.includes("/result")) {
|
} else if (uri.includes("/result")) {
|
||||||
this.setState({selectedMenuKey: "/result"});
|
this.setState({selectedMenuKey: "/result"});
|
||||||
} else if (uri.includes("/sysinfo")) {
|
|
||||||
this.setState({selectedMenuKey: "/sysinfo"});
|
|
||||||
} else if (uri.includes("/subscriptions")) {
|
|
||||||
this.setState({selectedMenuKey: "/subscriptions"});
|
|
||||||
} else if (uri.includes("/plans")) {
|
|
||||||
this.setState({selectedMenuKey: "/plans"});
|
|
||||||
} else if (uri.includes("/pricings")) {
|
|
||||||
this.setState({selectedMenuKey: "/pricings"});
|
|
||||||
} else {
|
} else {
|
||||||
this.setState({selectedMenuKey: -1});
|
this.setState({selectedMenuKey: -1});
|
||||||
}
|
}
|
||||||
@ -431,7 +401,7 @@ class App extends Component {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/">{i18next.t("general:Home")}</Link>, "/"));
|
res.push(Setting.getItem(<Link to="/">{i18next.t("general:Home")}</Link>, "/", <HomeTwoTone />));
|
||||||
|
|
||||||
if (Setting.isLocalAdminUser(this.state.account)) {
|
if (Setting.isLocalAdminUser(this.state.account)) {
|
||||||
if (Conf.ShowGithubCorner) {
|
if (Conf.ShowGithubCorner) {
|
||||||
@ -442,109 +412,54 @@ class App extends Component {
|
|||||||
</a>, "#"));
|
</a>, "#"));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/organizations">{i18next.t("general:Organizations")}</Link>,
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/organizations">{i18next.t("general:User Management")}</Link>, "/orgs", <AppstoreTwoTone />, [
|
||||||
"/organizations"));
|
Setting.getItem(<Link to="/organizations">{i18next.t("general:Organizations")}</Link>, "/organizations"),
|
||||||
|
Setting.getItem(<Link to="/groups">{i18next.t("general:Groups")}</Link>, "/groups"),
|
||||||
|
Setting.getItem(<Link to="/users">{i18next.t("general:Users")}</Link>, "/users"),
|
||||||
|
]));
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/groups">{i18next.t("general:Groups")}</Link>,
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/roles">{i18next.t("general:Authorization")}</Link>, "/auth", <SafetyCertificateTwoTone />, [
|
||||||
"/groups"));
|
Setting.getItem(<Link to="/roles">{i18next.t("general:Roles")}</Link>, "/roles"),
|
||||||
|
Setting.getItem(<Link to="/permissions">{i18next.t("general:Permissions")}</Link>, "/permissions"),
|
||||||
res.push(Setting.getItem(<Link to="/users">{i18next.t("general:Users")}</Link>,
|
Setting.getItem(<Link to="/models">{i18next.t("general:Models")}</Link>, "/models"),
|
||||||
"/users"
|
Setting.getItem(<Link to="/adapters">{i18next.t("general:Adapters")}</Link>, "/adapters"),
|
||||||
));
|
Setting.getItem(<Link to="/enforcers">{i18next.t("general:Enforcers")}</Link>, "/enforcers"),
|
||||||
|
].filter(item => {
|
||||||
res.push(Setting.getItem(<Link to="/roles">{i18next.t("general:Roles")}</Link>,
|
if (!Setting.isLocalAdminUser(this.state.account) && ["/models", "/adapters", "/enforcers"].includes(item.key)) {
|
||||||
"/roles"
|
return false;
|
||||||
));
|
} else {
|
||||||
|
return true;
|
||||||
res.push(Setting.getItem(<Link to="/permissions">{i18next.t("general:Permissions")}</Link>,
|
}
|
||||||
"/permissions"
|
})));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting.isLocalAdminUser(this.state.account)) {
|
if (Setting.isLocalAdminUser(this.state.account)) {
|
||||||
res.push(Setting.getItem(<Link to="/models">{i18next.t("general:Models")}</Link>,
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/applications">{i18next.t("general:Identity")}</Link>, "/identity", <LockTwoTone />, [
|
||||||
"/models"
|
Setting.getItem(<Link to="/applications">{i18next.t("general:Applications")}</Link>, "/applications"),
|
||||||
));
|
Setting.getItem(<Link to="/providers">{i18next.t("general:Providers")}</Link>, "/providers"),
|
||||||
|
Setting.getItem(<Link to="/resources">{i18next.t("general:Resources")}</Link>, "/resources"),
|
||||||
|
Setting.getItem(<Link to="/certs">{i18next.t("general:Certs")}</Link>, "/certs"),
|
||||||
|
]));
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/adapters">{i18next.t("general:Adapters")}</Link>,
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/records">{i18next.t("general:Logging & Auditing")}</Link>, "/logs", <WalletTwoTone />, [
|
||||||
"/adapters"
|
Setting.getItem(<Link to="/records">{i18next.t("general:Records")}</Link>, "/records"),
|
||||||
));
|
Setting.getItem(<Link to="/tokens">{i18next.t("general:Tokens")}</Link>, "/tokens"),
|
||||||
|
Setting.getItem(<Link to="/sessions">{i18next.t("general:Sessions")}</Link>, "/sessions"),
|
||||||
|
]));
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/enforcers">{i18next.t("general:Enforcers")}</Link>,
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/products">{i18next.t("general:Business & Payments")}</Link>, "/business", <DollarTwoTone />, [
|
||||||
"/enforcers"
|
Setting.getItem(<Link to="/products">{i18next.t("general:Products")}</Link>, "/products"),
|
||||||
));
|
Setting.getItem(<Link to="/payments">{i18next.t("general:Payments")}</Link>, "/payments"),
|
||||||
}
|
Setting.getItem(<Link to="/plans">{i18next.t("general:Plans")}</Link>, "/plans"),
|
||||||
|
Setting.getItem(<Link to="/pricings">{i18next.t("general:Pricings")}</Link>, "/pricings"),
|
||||||
|
Setting.getItem(<Link to="/subscriptions">{i18next.t("general:Subscriptions")}</Link>, "/subscriptions"),
|
||||||
|
]));
|
||||||
|
|
||||||
if (Setting.isLocalAdminUser(this.state.account)) {
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/sysinfo">{i18next.t("general:Admin")}</Link>, "/admin", <SettingTwoTone />, [
|
||||||
res.push(Setting.getItem(<Link to="/applications">{i18next.t("general:Applications")}</Link>,
|
Setting.getItem(<Link to="/sysinfo">{i18next.t("general:System Info")}</Link>, "/sysinfo"),
|
||||||
"/applications"
|
Setting.getItem(<Link to="/syncers">{i18next.t("general:Syncers")}</Link>, "/syncers"),
|
||||||
));
|
Setting.getItem(<Link to="/webhooks">{i18next.t("general:Webhooks")}</Link>, "/webhooks"),
|
||||||
|
Setting.getItem(<a target="_blank" rel="noreferrer" href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>{i18next.t("general:Swagger")}</a>, "/swagger")]));
|
||||||
res.push(Setting.getItem(<Link to="/providers">{i18next.t("general:Providers")}</Link>,
|
|
||||||
"/providers"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/resources">{i18next.t("general:Resources")}</Link>,
|
|
||||||
"/resources"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/records">{i18next.t("general:Records")}</Link>,
|
|
||||||
"/records"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/plans">{i18next.t("general:Plans")}</Link>,
|
|
||||||
"/plans"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/pricings">{i18next.t("general:Pricings")}</Link>,
|
|
||||||
"/pricings"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/subscriptions">{i18next.t("general:Subscriptions")}</Link>,
|
|
||||||
"/subscriptions"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Setting.isLocalAdminUser(this.state.account)) {
|
|
||||||
res.push(Setting.getItem(<Link to="/tokens">{i18next.t("general:Tokens")}</Link>,
|
|
||||||
"/tokens"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/sessions">{i18next.t("general:Sessions")}</Link>,
|
|
||||||
"/sessions"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/webhooks">{i18next.t("general:Webhooks")}</Link>,
|
|
||||||
"/webhooks"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/syncers">{i18next.t("general:Syncers")}</Link>,
|
|
||||||
"/syncers"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/certs">{i18next.t("general:Certs")}</Link>,
|
|
||||||
"/certs"
|
|
||||||
));
|
|
||||||
|
|
||||||
if (Conf.EnableExtraPages) {
|
|
||||||
res.push(Setting.getItem(<Link to="/products">{i18next.t("general:Products")}</Link>,
|
|
||||||
"/products"
|
|
||||||
));
|
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link to="/payments">{i18next.t("general:Payments")}</Link>,
|
|
||||||
"/payments"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Setting.isAdminUser(this.state.account)) {
|
|
||||||
res.push(Setting.getItem(<Link to="/sysinfo">{i18next.t("general:System Info")}</Link>,
|
|
||||||
"/sysinfo"
|
|
||||||
));
|
|
||||||
res.push(Setting.getItem(<a target="_blank" rel="noreferrer"
|
|
||||||
href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>{i18next.t("general:Swagger")}</a>,
|
|
||||||
"/swagger"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -20,8 +20,6 @@ export const IsDemoMode = false;
|
|||||||
export const ForceLanguage = "";
|
export const ForceLanguage = "";
|
||||||
export const DefaultLanguage = "en";
|
export const DefaultLanguage = "en";
|
||||||
|
|
||||||
export const EnableExtraPages = true;
|
|
||||||
|
|
||||||
export const InitThemeAlgorithm = true;
|
export const InitThemeAlgorithm = true;
|
||||||
export const ThemeDefault = {
|
export const ThemeDefault = {
|
||||||
themeType: "default",
|
themeType: "default",
|
||||||
|
@ -221,6 +221,7 @@ class GroupTreePage extends React.Component {
|
|||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
organizationName: value,
|
organizationName: value,
|
||||||
|
groupName: "",
|
||||||
});
|
});
|
||||||
this.props.history.push(`/trees/${value}`);
|
this.props.history.push(`/trees/${value}`);
|
||||||
}}
|
}}
|
||||||
|
@ -163,7 +163,7 @@ class PaymentEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input disabled={true} value={this.state.payment.organization} onChange={e => {
|
<Input disabled={true} value={this.state.payment.owner} onChange={e => {
|
||||||
// this.updatePaymentField('organization', e.target.value);
|
// this.updatePaymentField('organization', e.target.value);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -115,6 +115,26 @@ class PaymentResultPage extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (payment.state === "Canceled") {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
Setting.renderHelmet(payment)
|
||||||
|
}
|
||||||
|
<Result
|
||||||
|
status="warning"
|
||||||
|
title={`${i18next.t("payment:The payment has been canceled")}: ${payment.productDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
|
||||||
|
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
||||||
|
extra={[
|
||||||
|
<Button type="primary" key="returnUrl" onClick={() => {
|
||||||
|
this.goToPaymentUrl(payment);
|
||||||
|
}}>
|
||||||
|
{i18next.t("payment:Return to Website")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -124,7 +144,7 @@ class PaymentResultPage extends React.Component {
|
|||||||
<Result
|
<Result
|
||||||
status="error"
|
status="error"
|
||||||
title={`${i18next.t("payment:The payment has failed")}: ${payment.productDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
|
title={`${i18next.t("payment:The payment has failed")}: ${payment.productDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}`}
|
||||||
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
subTitle={`${i18next.t("payment:Failed reason")}: ${payment.message}`}
|
||||||
extra={[
|
extra={[
|
||||||
<Button type="primary" key="returnUrl" onClick={() => {
|
<Button type="primary" key="returnUrl" onClick={() => {
|
||||||
this.goToPaymentUrl(payment);
|
this.goToPaymentUrl(payment);
|
||||||
|
@ -134,10 +134,14 @@ class ProviderEditPage extends React.Component {
|
|||||||
case "Email":
|
case "Email":
|
||||||
return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"));
|
return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"));
|
||||||
case "SMS":
|
case "SMS":
|
||||||
if (provider.type === "Volc Engine SMS") {
|
if (provider.type === "Volc Engine SMS" || provider.type === "Amazon SNS" || provider.type === "Baidu Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
|
||||||
} else if (provider.type === "Huawei Cloud SMS") {
|
} else if (provider.type === "Huawei Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"));
|
||||||
|
} else if (provider.type === "UCloud SMS") {
|
||||||
|
return Setting.getLabel(i18next.t("provider:Public key"), i18next.t("provider:Public key - Tooltip"));
|
||||||
|
} else if (provider.type === "Msg91 SMS" || provider.type === "Infobip SMS") {
|
||||||
|
return Setting.getLabel(i18next.t("provider:Sender Id"), i18next.t("provider:Sender Id - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
|
||||||
}
|
}
|
||||||
@ -157,10 +161,16 @@ class ProviderEditPage extends React.Component {
|
|||||||
case "Email":
|
case "Email":
|
||||||
return Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"));
|
return Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"));
|
||||||
case "SMS":
|
case "SMS":
|
||||||
if (provider.type === "Volc Engine SMS") {
|
if (provider.type === "Volc Engine SMS" || provider.type === "Amazon SNS" || provider.type === "Baidu Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:Secret access key - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:Secret access key - Tooltip"));
|
||||||
} else if (provider.type === "Huawei Cloud SMS") {
|
} else if (provider.type === "Huawei Cloud SMS") {
|
||||||
return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip"));
|
||||||
|
} else if (provider.type === "UCloud SMS") {
|
||||||
|
return Setting.getLabel(i18next.t("provider:Private Key"), i18next.t("provider:Private Key - Tooltip"));
|
||||||
|
} else if (provider.type === "Msg91 SMS") {
|
||||||
|
return Setting.getLabel(i18next.t("provider:Auth Key"), i18next.t("provider:Auth Key - Tooltip"));
|
||||||
|
} else if (provider.type === "Infobip SMS") {
|
||||||
|
return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip"));
|
||||||
} else {
|
} else {
|
||||||
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
||||||
}
|
}
|
||||||
@ -234,7 +244,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
tooltip = i18next.t("provider:Agent ID - Tooltip");
|
tooltip = i18next.t("provider:Agent ID - Tooltip");
|
||||||
}
|
}
|
||||||
} else if (provider.category === "SMS") {
|
} else if (provider.category === "SMS") {
|
||||||
if (provider.type === "Twilio SMS") {
|
if (provider.type === "Twilio SMS" || provider.type === "Azure ACS") {
|
||||||
text = i18next.t("provider:Sender number");
|
text = i18next.t("provider:Sender number");
|
||||||
tooltip = i18next.t("provider:Sender number - Tooltip");
|
tooltip = i18next.t("provider:Sender number - Tooltip");
|
||||||
} else if (provider.type === "Tencent Cloud SMS") {
|
} else if (provider.type === "Tencent Cloud SMS") {
|
||||||
@ -246,6 +256,18 @@ class ProviderEditPage extends React.Component {
|
|||||||
} else if (provider.type === "Huawei Cloud SMS") {
|
} else if (provider.type === "Huawei Cloud SMS") {
|
||||||
text = i18next.t("provider:Channel No.");
|
text = i18next.t("provider:Channel No.");
|
||||||
tooltip = i18next.t("provider:Channel No. - Tooltip");
|
tooltip = i18next.t("provider:Channel No. - Tooltip");
|
||||||
|
} else if (provider.type === "Amazon SNS") {
|
||||||
|
text = i18next.t("provider:Region");
|
||||||
|
tooltip = i18next.t("provider:Region - Tooltip");
|
||||||
|
} else if (provider.type === "Baidu Cloud SMS") {
|
||||||
|
text = i18next.t("provider:Endpoint");
|
||||||
|
tooltip = i18next.t("provider:Endpoint - Tooltip");
|
||||||
|
} else if (provider.type === "Infobip SMS") {
|
||||||
|
text = i18next.t("provider:Base URL");
|
||||||
|
tooltip = i18next.t("provider:Base URL - Tooltip");
|
||||||
|
} else if (provider.type === "UCloud SMS") {
|
||||||
|
text = i18next.t("provider:Project Id");
|
||||||
|
tooltip = i18next.t("provider:Project Id - Tooltip");
|
||||||
}
|
}
|
||||||
} else if (provider.category === "Email") {
|
} else if (provider.category === "Email") {
|
||||||
if (provider.type === "SUBMAIL") {
|
if (provider.type === "SUBMAIL") {
|
||||||
@ -622,7 +644,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
{["Local File System", "MinIO", "Tencent Cloud COS"].includes(this.state.provider.type) ? null : (
|
{["Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={2}>
|
<Col style={{marginTop: "5px"}} span={2}>
|
||||||
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
|
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
|
||||||
@ -656,7 +678,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{["MinIO"].includes(this.state.provider.type) ? null : (
|
{["MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={2}>
|
<Col style={{marginTop: "5px"}} span={2}>
|
||||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||||
@ -668,7 +690,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
{["AWS S3", "Tencent Cloud COS"].includes(this.state.provider.type) ? (
|
{["AWS S3", "Tencent Cloud COS", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? (
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={2}>
|
<Col style={{marginTop: "5px"}} span={2}>
|
||||||
{Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :
|
{Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :
|
||||||
@ -757,7 +779,7 @@ class ProviderEditPage extends React.Component {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : this.state.provider.category === "SMS" ? (
|
) : this.state.provider.category === "SMS" ? (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{this.state.provider.type === "Twilio SMS" ?
|
{["Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
|
||||||
null :
|
null :
|
||||||
(<Row style={{marginTop: "20px"}} >
|
(<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
@ -771,16 +793,20 @@ class ProviderEditPage extends React.Component {
|
|||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<Row style={{marginTop: "20px"}} >
|
{["Infobip SMS"].includes(this.state.provider.type) ?
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
null :
|
||||||
{Setting.getLabel(i18next.t("provider:Template code"), i18next.t("provider:Template code - Tooltip"))} :
|
(<Row style={{marginTop: "20px"}} >
|
||||||
</Col>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
<Col span={22} >
|
{Setting.getLabel(i18next.t("provider:Template code"), i18next.t("provider:Template code - Tooltip"))} :
|
||||||
<Input value={this.state.provider.templateCode} onChange={e => {
|
</Col>
|
||||||
this.updateProviderField("templateCode", e.target.value);
|
<Col span={22} >
|
||||||
}} />
|
<Input value={this.state.provider.templateCode} onChange={e => {
|
||||||
</Col>
|
this.updateProviderField("templateCode", e.target.value);
|
||||||
</Row>
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
}
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("provider:SMS Test"), i18next.t("provider:SMS Test - Tooltip"))} :
|
{Setting.getLabel(i18next.t("provider:SMS Test"), i18next.t("provider:SMS Test - Tooltip"))} :
|
||||||
|
@ -37,7 +37,7 @@ class ProviderListPage extends BaseListPage {
|
|||||||
|
|
||||||
newProvider() {
|
newProvider() {
|
||||||
const randomName = Setting.getRandomName();
|
const randomName = Setting.getRandomName();
|
||||||
const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization();
|
const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization(this.props.account);
|
||||||
return {
|
return {
|
||||||
owner: owner,
|
owner: owner,
|
||||||
name: `provider_${randomName}`,
|
name: `provider_${randomName}`,
|
||||||
|
@ -85,10 +85,26 @@ export const OtherProviderInfo = {
|
|||||||
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
|
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
|
||||||
url: "https://aliyun.com/product/sms",
|
url: "https://aliyun.com/product/sms",
|
||||||
},
|
},
|
||||||
|
"Amazon SNS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_aws.png`,
|
||||||
|
url: "https://aws.amazon.com/cn/sns/",
|
||||||
|
},
|
||||||
|
"Azure ACS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_azure.png`,
|
||||||
|
url: "https://azure.microsoft.com/en-us/products/communication-services",
|
||||||
|
},
|
||||||
|
"Infobip SMS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_infobip.png`,
|
||||||
|
url: "https://portal.infobip.com/homepage/",
|
||||||
|
},
|
||||||
"Tencent Cloud SMS": {
|
"Tencent Cloud SMS": {
|
||||||
logo: `${StaticBaseUrl}/img/social_tencent_cloud.jpg`,
|
logo: `${StaticBaseUrl}/img/social_tencent_cloud.jpg`,
|
||||||
url: "https://cloud.tencent.com/product/sms",
|
url: "https://cloud.tencent.com/product/sms",
|
||||||
},
|
},
|
||||||
|
"Baidu Cloud SMS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_baidu_cloud.png`,
|
||||||
|
url: "https://cloud.baidu.com/product/sms.html",
|
||||||
|
},
|
||||||
"Volc Engine SMS": {
|
"Volc Engine SMS": {
|
||||||
logo: `${StaticBaseUrl}/img/social_volc_engine.jpg`,
|
logo: `${StaticBaseUrl}/img/social_volc_engine.jpg`,
|
||||||
url: "https://www.volcengine.com/products/cloud-sms",
|
url: "https://www.volcengine.com/products/cloud-sms",
|
||||||
@ -97,6 +113,10 @@ export const OtherProviderInfo = {
|
|||||||
logo: `${StaticBaseUrl}/img/social_huawei.png`,
|
logo: `${StaticBaseUrl}/img/social_huawei.png`,
|
||||||
url: "https://www.huaweicloud.com/product/msgsms.html",
|
url: "https://www.huaweicloud.com/product/msgsms.html",
|
||||||
},
|
},
|
||||||
|
"UCloud SMS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_ucloud.png`,
|
||||||
|
url: "https://www.ucloud.cn/site/product/usms.html",
|
||||||
|
},
|
||||||
"Twilio SMS": {
|
"Twilio SMS": {
|
||||||
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
|
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
|
||||||
url: "https://www.twilio.com/messaging",
|
url: "https://www.twilio.com/messaging",
|
||||||
@ -109,6 +129,10 @@ export const OtherProviderInfo = {
|
|||||||
logo: `${StaticBaseUrl}/img/social_submail.svg`,
|
logo: `${StaticBaseUrl}/img/social_submail.svg`,
|
||||||
url: "https://www.mysubmail.com",
|
url: "https://www.mysubmail.com",
|
||||||
},
|
},
|
||||||
|
"Msg91 SMS": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_msg91.ico`,
|
||||||
|
url: "https://control.msg91.com/app/",
|
||||||
|
},
|
||||||
"Mock SMS": {
|
"Mock SMS": {
|
||||||
logo: `${StaticBaseUrl}/img/social_default.png`,
|
logo: `${StaticBaseUrl}/img/social_default.png`,
|
||||||
url: "",
|
url: "",
|
||||||
@ -153,6 +177,14 @@ export const OtherProviderInfo = {
|
|||||||
logo: `${StaticBaseUrl}/img/social_azure.png`,
|
logo: `${StaticBaseUrl}/img/social_azure.png`,
|
||||||
url: "https://azure.microsoft.com/en-us/services/storage/blobs/",
|
url: "https://azure.microsoft.com/en-us/services/storage/blobs/",
|
||||||
},
|
},
|
||||||
|
"Qiniu Cloud Kodo": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_qiniu_cloud.png`,
|
||||||
|
url: "https://www.qiniu.com/solutions/storage",
|
||||||
|
},
|
||||||
|
"Google Cloud Storage": {
|
||||||
|
logo: `${StaticBaseUrl}/img/social_google_cloud.png`,
|
||||||
|
url: "https://cloud.google.com/storage",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
SAML: {
|
SAML: {
|
||||||
"Aliyun IDaaS": {
|
"Aliyun IDaaS": {
|
||||||
@ -853,13 +885,19 @@ export function getProviderTypeOptions(category) {
|
|||||||
} else if (category === "SMS") {
|
} else if (category === "SMS") {
|
||||||
return (
|
return (
|
||||||
[
|
[
|
||||||
{id: "Aliyun SMS", name: "Aliyun SMS"},
|
{id: "Aliyun SMS", name: "Alibaba Cloud SMS"},
|
||||||
|
{id: "Amazon SNS", name: "Amazon SNS"},
|
||||||
|
{id: "Azure ACS", name: "Azure ACS"},
|
||||||
|
{id: "Infobip SMS", name: "Infobip SMS"},
|
||||||
{id: "Tencent Cloud SMS", name: "Tencent Cloud SMS"},
|
{id: "Tencent Cloud SMS", name: "Tencent Cloud SMS"},
|
||||||
|
{id: "Baidu Cloud SMS", name: "Baidu Cloud SMS"},
|
||||||
{id: "Volc Engine SMS", name: "Volc Engine SMS"},
|
{id: "Volc Engine SMS", name: "Volc Engine SMS"},
|
||||||
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
|
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
|
||||||
|
{id: "UCloud SMS", name: "UCloud SMS"},
|
||||||
{id: "Twilio SMS", name: "Twilio SMS"},
|
{id: "Twilio SMS", name: "Twilio SMS"},
|
||||||
{id: "SmsBao SMS", name: "SmsBao SMS"},
|
{id: "SmsBao SMS", name: "SmsBao SMS"},
|
||||||
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
|
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
|
||||||
|
{id: "Msg91 SMS", name: "Msg91 SMS"},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else if (category === "Storage") {
|
} else if (category === "Storage") {
|
||||||
@ -871,6 +909,8 @@ export function getProviderTypeOptions(category) {
|
|||||||
{id: "Aliyun OSS", name: "Aliyun OSS"},
|
{id: "Aliyun OSS", name: "Aliyun OSS"},
|
||||||
{id: "Tencent Cloud COS", name: "Tencent Cloud COS"},
|
{id: "Tencent Cloud COS", name: "Tencent Cloud COS"},
|
||||||
{id: "Azure Blob", name: "Azure Blob"},
|
{id: "Azure Blob", name: "Azure Blob"},
|
||||||
|
{id: "Qiniu Cloud Kodo", name: "Qiniu Cloud Kodo"},
|
||||||
|
{id: "Google Cloud Storage", name: "Google Cloud Storage"},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else if (category === "SAML") {
|
} else if (category === "SAML") {
|
||||||
@ -1043,13 +1083,7 @@ export function getLabel(text, tooltip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getItem(label, key, icon, children, type) {
|
export function getItem(label, key, icon, children, type) {
|
||||||
return {
|
return {label: label, key: key, icon: icon, children: children, type: type};
|
||||||
key,
|
|
||||||
icon,
|
|
||||||
children,
|
|
||||||
label,
|
|
||||||
type,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOption(label, value) {
|
export function getOption(label, value) {
|
||||||
@ -1179,11 +1213,11 @@ export function isDefaultOrganizationSelected(account) {
|
|||||||
|
|
||||||
const BuiltInObjects = [
|
const BuiltInObjects = [
|
||||||
"api-enforcer-built-in",
|
"api-enforcer-built-in",
|
||||||
"permission-enforcer-built-in",
|
"user-enforcer-built-in",
|
||||||
"api-model-built-in",
|
"api-model-built-in",
|
||||||
"permission-model-built-in",
|
"user-model-built-in",
|
||||||
"api-adapter-built-in",
|
"api-adapter-built-in",
|
||||||
"permission-adapter-built-in",
|
"user-adapter-built-in",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function builtInObject(obj) {
|
export function builtInObject(obj) {
|
||||||
|
@ -133,13 +133,25 @@ class UserEditPage extends React.Component {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
application: res.data,
|
application: res.data,
|
||||||
isGroupsVisible: res.data?.organizationObj.accountItems?.some((item) => item.name === "Groups" && item.visible),
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUserOrganization() {
|
||||||
|
return this.state.organizations.filter(organization => organization.name === this.state.user.owner)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
isGroupsVisible() {
|
||||||
|
const organization = this.getUserOrganization();
|
||||||
|
if (!organization) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return organization.accountItems?.some((item) => item.name === "Groups" && item.visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getGroups(organizationName) {
|
getGroups(organizationName) {
|
||||||
if (this.state.isGroupsVisible) {
|
if (this.isGroupsVisible()) {
|
||||||
GroupBackend.getGroups(organizationName)
|
GroupBackend.getGroups(organizationName)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
@ -319,7 +331,7 @@ class UserEditPage extends React.Component {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
this.state.groups?.map((group) => <Option key={group.name} value={group.name}>
|
this.state.groups?.map((group) => <Option key={group.name} value={`${group.owner}/${group.name}`}>
|
||||||
<Space>
|
<Space>
|
||||||
{group.type === "Physical" ? <UsergroupAddOutlined /> : <HolderOutlined />}
|
{group.type === "Physical" ? <UsergroupAddOutlined /> : <HolderOutlined />}
|
||||||
{group.displayName}
|
{group.displayName}
|
||||||
@ -401,7 +413,7 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<PasswordModal user={this.state.user} organization={this.state.application?.organizationObj} account={this.props.account} disabled={disabled} />
|
<PasswordModal user={this.state.user} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
@ -442,7 +454,7 @@ class UserEditPage extends React.Component {
|
|||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
this.updateUserField("countryCode", value);
|
this.updateUserField("countryCode", value);
|
||||||
}}
|
}}
|
||||||
countryCodes={this.state.application?.organizationObj.countryCodes}
|
countryCodes={this.getUserOrganization()?.countryCodes}
|
||||||
/>
|
/>
|
||||||
<Input value={this.state.user.phone}
|
<Input value={this.state.user.phone}
|
||||||
style={{width: "70%"}}
|
style={{width: "70%"}}
|
||||||
@ -599,10 +611,10 @@ class UserEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
{
|
{
|
||||||
this.state.application?.organizationObj.tags?.length > 0 ? (
|
this.getUserOrganization()?.tags?.length > 0 ? (
|
||||||
<Select virtual={false} style={{width: "100%"}} value={this.state.user.tag}
|
<Select virtual={false} style={{width: "100%"}} value={this.state.user.tag}
|
||||||
onChange={(value => {this.updateUserField("tag", value);})}
|
onChange={(value => {this.updateUserField("tag", value);})}
|
||||||
options={this.state.application.organizationObj.tags?.map((tag) => {
|
options={this.getUserOrganization()?.tags?.map((tag) => {
|
||||||
const tokens = tag.split("|");
|
const tokens = tag.split("|");
|
||||||
const value = tokens[0];
|
const value = tokens[0];
|
||||||
const displayValue = Setting.getLanguage() !== "zh" ? tokens[0] : tokens[1];
|
const displayValue = Setting.getLanguage() !== "zh" ? tokens[0] : tokens[1];
|
||||||
@ -888,7 +900,7 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("mfa:Multi-factor authentication"), i18next.t("mfa:Multi-factor authentication - Tooltip "))} :
|
{Setting.getLabel(i18next.t("mfa:Multi-factor authentication"), i18next.t("mfa:Multi-factor authentication - Tooltip "))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Card title={i18next.t("mfa:Multi-factor methods")}
|
<Card size="small" title={i18next.t("mfa:Multi-factor methods")}
|
||||||
extra={this.state.multiFactorAuths?.some(mfaProps => mfaProps.enabled) ?
|
extra={this.state.multiFactorAuths?.some(mfaProps => mfaProps.enabled) ?
|
||||||
<PopconfirmModal
|
<PopconfirmModal
|
||||||
text={i18next.t("general:Disable")}
|
text={i18next.t("general:Disable")}
|
||||||
@ -1008,7 +1020,7 @@ class UserEditPage extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||||
{
|
{
|
||||||
this.state.application?.organizationObj.accountItems?.map(accountItem => {
|
this.getUserOrganization()?.accountItems?.map(accountItem => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={accountItem.name}>
|
<React.Fragment key={accountItem.name}>
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,7 @@ class UserListPage extends BaseListPage {
|
|||||||
phone: Setting.getRandomNumber(),
|
phone: Setting.getRandomNumber(),
|
||||||
countryCode: this.state.organization.countryCodes?.length > 0 ? this.state.organization.countryCodes[0] : "",
|
countryCode: this.state.organization.countryCodes?.length > 0 ? this.state.organization.countryCodes[0] : "",
|
||||||
address: [],
|
address: [],
|
||||||
groups: this.props.groupName ? [this.props.groupName] : [],
|
groups: this.props.groupName ? [`${owner}/${this.props.groupName}`] : [],
|
||||||
affiliation: "Example Inc.",
|
affiliation: "Example Inc.",
|
||||||
tag: "staff",
|
tag: "staff",
|
||||||
region: "",
|
region: "",
|
||||||
|
@ -287,10 +287,10 @@ class PolicyTable extends React.Component {
|
|||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip placement="topLeft" title="Edit">
|
<Tooltip placement="topLeft" title="Edit">
|
||||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
|
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip placement="topLeft" title="Delete">
|
<Tooltip placement="topLeft" title="Delete">
|
||||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
|
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -304,14 +304,14 @@ class PolicyTable extends React.Component {
|
|||||||
onChange: (page) => this.setState({
|
onChange: (page) => this.setState({
|
||||||
page: page,
|
page: page,
|
||||||
}),
|
}),
|
||||||
disabled: this.state.editingIndex !== "",
|
disabled: this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name}),
|
||||||
current: this.state.page,
|
current: this.state.page,
|
||||||
}}
|
}}
|
||||||
columns={columns} dataSource={table} rowKey="key" size="middle" bordered
|
columns={columns} dataSource={table} rowKey="key" size="middle" bordered
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
title={() => (
|
title={() => (
|
||||||
<div>
|
<div>
|
||||||
<Button disabled={this.state.editingIndex !== ""} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -38,7 +38,7 @@ class SyncerTableColumnTable extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addRow(table) {
|
addRow(table) {
|
||||||
const row = {name: `column${table.length}`, type: "string", values: []};
|
const row = {name: `column${table.length}`, type: "string", values: [], isKey: table.filter(row => row.isKey).length === 0};
|
||||||
if (table === undefined) {
|
if (table === undefined) {
|
||||||
table = [];
|
table = [];
|
||||||
}
|
}
|
||||||
@ -107,6 +107,26 @@ class SyncerTableColumnTable extends React.Component {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("syncer:Is key"),
|
||||||
|
dataIndex: "isKey",
|
||||||
|
key: "isKey",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Switch checked={text} onChange={checked => {
|
||||||
|
if (!record.isKey && checked) {
|
||||||
|
table.forEach((row, i) => {
|
||||||
|
this.updateField(table, i, "isKey", false);
|
||||||
|
});
|
||||||
|
} else if (record.isKey && !checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateField(table, index, "isKey", checked);
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18next.t("syncer:Is hashed"),
|
title: i18next.t("syncer:Is hashed"),
|
||||||
dataIndex: "isHashed",
|
dataIndex: "isHashed",
|
||||||
@ -133,7 +153,7 @@ class SyncerTableColumnTable extends React.Component {
|
|||||||
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
|
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
|
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
|
||||||
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
|
<Button icon={<DeleteOutlined />} disabled={record.isKey && table.length > 1} size="small" onClick={() => this.deleteRow(table, index)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -29,7 +29,20 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@ctrl/tinycolor" "^3.4.0"
|
"@ctrl/tinycolor" "^3.4.0"
|
||||||
|
|
||||||
"@ant-design/cssinjs@^1", "@ant-design/cssinjs@^1.10.1", "@ant-design/cssinjs@^1.5.6", "@ant-design/cssinjs@^1.8.1":
|
"@ant-design/cssinjs@1.16.1":
|
||||||
|
version "1.16.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.16.1.tgz#0032044db5678dd25ac12def1abb1d52e6a4d583"
|
||||||
|
integrity sha512-KKVB5Or6BDC1Bo3Y4KMlOkyQU0P+6GTodubrQ9YfrtXG1TgO4wpaEfg9I4ZA49R7M+Ij2KKNwb+5abvmXy6K8w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.11.1"
|
||||||
|
"@emotion/hash" "^0.8.0"
|
||||||
|
"@emotion/unitless" "^0.7.5"
|
||||||
|
classnames "^2.3.1"
|
||||||
|
csstype "^3.0.10"
|
||||||
|
rc-util "^5.35.0"
|
||||||
|
stylis "^4.0.13"
|
||||||
|
|
||||||
|
"@ant-design/cssinjs@^1", "@ant-design/cssinjs@^1.10.1", "@ant-design/cssinjs@^1.5.6":
|
||||||
version "1.10.1"
|
version "1.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.10.1.tgz#c9173f38e3d61f0883ca3c17d7cf1e30784e0dd7"
|
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.10.1.tgz#c9173f38e3d61f0883ca3c17d7cf1e30784e0dd7"
|
||||||
integrity sha512-PSoJS8RMzn95ZRg007dJGr6AU0Zim/O+tTN0xmXmh9CkIl4y3wuOr2Zhehaj7s130wPSYDVvahf3DKT50w/Zhw==
|
integrity sha512-PSoJS8RMzn95ZRg007dJGr6AU0Zim/O+tTN0xmXmh9CkIl4y3wuOr2Zhehaj7s130wPSYDVvahf3DKT50w/Zhw==
|
||||||
@ -10100,6 +10113,14 @@ rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.
|
|||||||
"@babel/runtime" "^7.18.3"
|
"@babel/runtime" "^7.18.3"
|
||||||
react-is "^16.12.0"
|
react-is "^16.12.0"
|
||||||
|
|
||||||
|
rc-util@^5.35.0:
|
||||||
|
version "5.35.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.35.0.tgz#bed1986248b7be525cc0894109e609ac60207f29"
|
||||||
|
integrity sha512-MTXlixb3EoSTEchsOc7XWsVyoUQqoCsh2Z1a2IptwNgqleMF6ZgQeY52UzUbNj5CcVBg9YljOWjuOV07jSSm4Q==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.18.3"
|
||||||
|
react-is "^16.12.0"
|
||||||
|
|
||||||
rc-virtual-list@^3.4.13, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
|
rc-virtual-list@^3.4.13, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
|
||||||
version "3.5.2"
|
version "3.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.5.2.tgz#5e1028869bae900eacbae6788d4eca7210736006"
|
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.5.2.tgz#5e1028869bae900eacbae6788d4eca7210736006"
|
||||||
|
Reference in New Issue
Block a user