@@ -0,0 +1,75 @@ | |||
package casdoor | |||
import ( | |||
"runtime" | |||
"github.com/astaxie/beego" | |||
_ "github.com/go-sql-driver/mysql" | |||
"xorm.io/xorm" | |||
) | |||
var adapter *Adapter = nil | |||
var CasdoorOrganization string | |||
type Session struct { | |||
SessionKey string `xorm:"char(64) notnull pk"` | |||
SessionData []uint8 `xorm:"blob"` | |||
SessionExpiry int `xorm:"notnull"` | |||
} | |||
func InitCasdoorAdapter() { | |||
casdoorDbName := beego.AppConfig.String("casdoorDbName") | |||
if casdoorDbName == "" { | |||
return | |||
} | |||
adapter = NewAdapter(beego.AppConfig.String("driverName"), beego.AppConfig.String("dataSourceName"), beego.AppConfig.String("casdoorDbName")) | |||
CasdoorOrganization = beego.AppConfig.String("casdoorOrganization") | |||
} | |||
// Adapter represents the MySQL adapter for policy storage. | |||
type Adapter struct { | |||
driverName string | |||
dataSourceName string | |||
dbName string | |||
Engine *xorm.Engine | |||
} | |||
// finalizer is the destructor for Adapter. | |||
func finalizer(a *Adapter) { | |||
err := a.Engine.Close() | |||
if err != nil { | |||
panic(err) | |||
} | |||
} | |||
// NewAdapter is the constructor for Adapter. | |||
func NewAdapter(driverName string, dataSourceName string, dbName string) *Adapter { | |||
a := &Adapter{} | |||
a.driverName = driverName | |||
a.dataSourceName = dataSourceName | |||
a.dbName = dbName | |||
// Open the DB, create it if not existed. | |||
a.open() | |||
// Call the destructor when the object is released. | |||
runtime.SetFinalizer(a, finalizer) | |||
return a | |||
} | |||
func (a *Adapter) open() { | |||
Engine, err := xorm.NewEngine(a.driverName, a.dataSourceName+a.dbName) | |||
if err != nil { | |||
panic(err) | |||
} | |||
a.Engine = Engine | |||
} | |||
func (a *Adapter) close() { | |||
a.Engine.Close() | |||
a.Engine = nil | |||
} |
@@ -0,0 +1,95 @@ | |||
package casdoor | |||
import ( | |||
"github.com/casbin/casbase/util" | |||
"xorm.io/core" | |||
) | |||
type Permission struct { | |||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"` | |||
Name string `xorm:"varchar(100) notnull pk" json:"name"` | |||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` | |||
DisplayName string `xorm:"varchar(100)" json:"displayName"` | |||
Users []string `xorm:"mediumtext" json:"users"` | |||
Roles []string `xorm:"mediumtext" json:"roles"` | |||
Domains []string `xorm:"mediumtext" json:"domains"` | |||
Model string `xorm:"varchar(100)" json:"model"` | |||
ResourceType string `xorm:"varchar(100)" json:"resourceType"` | |||
Resources []string `xorm:"mediumtext" json:"resources"` | |||
Actions []string `xorm:"mediumtext" json:"actions"` | |||
Effect string `xorm:"varchar(100)" json:"effect"` | |||
IsEnabled bool `json:"isEnabled"` | |||
Submitter string `xorm:"varchar(100)" json:"submitter"` | |||
Approver string `xorm:"varchar(100)" json:"approver"` | |||
ApproveTime string `xorm:"varchar(100)" json:"approveTime"` | |||
State string `xorm:"varchar(100)" json:"state"` | |||
} | |||
func GetPermissions(owner string) []*Permission { | |||
permissions := []*Permission{} | |||
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner}) | |||
if err != nil { | |||
panic(err) | |||
} | |||
return permissions | |||
} | |||
func getPermission(owner string, name string) *Permission { | |||
if owner == "" || name == "" { | |||
return nil | |||
} | |||
permission := Permission{Owner: owner, Name: name} | |||
existed, err := adapter.Engine.Get(&permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
if existed { | |||
return &permission | |||
} else { | |||
return nil | |||
} | |||
} | |||
func GetPermission(id string) *Permission { | |||
owner, name := util.GetOwnerAndNameFromId(id) | |||
return getPermission(owner, name) | |||
} | |||
func UpdatePermission(id string, permission *Permission) bool { | |||
owner, name := util.GetOwnerAndNameFromId(id) | |||
oldPermission := getPermission(owner, name) | |||
if oldPermission == nil { | |||
return false | |||
} | |||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
return affected != 0 | |||
} | |||
func AddPermission(permission *Permission) bool { | |||
affected, err := adapter.Engine.Insert(permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
return affected != 0 | |||
} | |||
func DeletePermission(permission *Permission) bool { | |||
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{}) | |||
if err != nil { | |||
panic(err) | |||
} | |||
return affected != 0 | |||
} |
@@ -3,6 +3,7 @@ httpport = 14000 | |||
runmode = dev | |||
SessionOn = true | |||
copyrequestbody = true | |||
driverName = mysql | |||
dataSourceName = root:123@tcp(localhost:3306)/ | |||
dbName = casbase | |||
redisEndpoint = | |||
@@ -10,5 +11,6 @@ landingFolder = casbase-landing | |||
casdoorEndpoint = http://localhost:8000 | |||
clientId = af6b5aa958822fb9dc33 | |||
clientSecret = 8bc3010c1c951c8d876b1f311a901ff8deeb93bc | |||
casdoorDbName = casdoor | |||
casdoorOrganization = "casbin" | |||
casdoorApplication = "app-casbase" |
@@ -0,0 +1,56 @@ | |||
package controllers | |||
import ( | |||
"encoding/json" | |||
"github.com/casbin/casbase/casdoor" | |||
) | |||
func (c *ApiController) GetPermissions() { | |||
owner := c.Input().Get("owner") | |||
c.Data["json"] = casdoor.GetPermissions(owner) | |||
c.ServeJSON() | |||
} | |||
func (c *ApiController) GetPermission() { | |||
id := c.Input().Get("id") | |||
c.Data["json"] = casdoor.GetPermission(id) | |||
c.ServeJSON() | |||
} | |||
func (c *ApiController) UpdatePermission() { | |||
id := c.Input().Get("id") | |||
var permission casdoor.Permission | |||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
c.Data["json"] = casdoor.UpdatePermission(id, &permission) | |||
c.ServeJSON() | |||
} | |||
func (c *ApiController) AddPermission() { | |||
var permission casdoor.Permission | |||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
c.Data["json"] = casdoor.AddPermission(&permission) | |||
c.ServeJSON() | |||
} | |||
func (c *ApiController) DeletePermission() { | |||
var permission casdoor.Permission | |||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) | |||
if err != nil { | |||
panic(err) | |||
} | |||
c.Data["json"] = casdoor.DeletePermission(&permission) | |||
c.ServeJSON() | |||
} |
@@ -4,12 +4,14 @@ import ( | |||
"github.com/astaxie/beego" | |||
"github.com/astaxie/beego/plugins/cors" | |||
_ "github.com/astaxie/beego/session/redis" | |||
"github.com/casbin/casbase/casdoor" | |||
"github.com/casbin/casbase/object" | |||
"github.com/casbin/casbase/routers" | |||
) | |||
func main() { | |||
object.InitAdapter() | |||
casdoor.InitCasdoorAdapter() | |||
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{ | |||
AllowOrigins: []string{"*"}, | |||
@@ -21,7 +21,7 @@ func InitConfig() { | |||
} | |||
func InitAdapter() { | |||
adapter = NewAdapter("mysql", beego.AppConfig.String("dataSourceName")) | |||
adapter = NewAdapter(beego.AppConfig.String("driverName"), beego.AppConfig.String("dataSourceName")) | |||
} | |||
// Adapter represents the MySQL adapter for policy storage. | |||
@@ -55,4 +55,10 @@ func initAPI() { | |||
beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile") | |||
beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile") | |||
beego.Router("/api/delete-file", &controllers.ApiController{}, "POST:DeleteFile") | |||
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions") | |||
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission") | |||
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission") | |||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission") | |||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission") | |||
} |
@@ -3,5 +3,5 @@ package storage | |||
import "testing" | |||
func TestStorage(t *testing.T) { | |||
ListObjects("casbase") | |||
ListObjects("casbase", "") | |||
} |
@@ -228,6 +228,13 @@ class App extends Component { | |||
</Link> | |||
</Menu.Item> | |||
); | |||
res.push( | |||
<Menu.Item key="/resources"> | |||
<a target="_blank" rel="noreferrer" href={Setting.getMyProfileUrl(this.state.account).replace("/account", "/permissions")}> | |||
{i18next.t("general:Permissions")} | |||
</a> | |||
</Menu.Item> | |||
); | |||
// res.push( | |||
// <Menu.Item key="/clustering"> | |||
// <Link to="/clustering"> | |||
@@ -1,11 +1,12 @@ | |||
import React from "react"; | |||
import {Button, Col, Empty, Input, Popconfirm, Row, Spin, Tooltip, Tree, Upload} from 'antd'; | |||
import {CloudUploadOutlined, createFromIconfontCN, DeleteOutlined, DownloadOutlined, FolderAddOutlined} from "@ant-design/icons"; | |||
import {CloudUploadOutlined, createFromIconfontCN, DeleteOutlined, DownloadOutlined, FileDoneOutlined, FolderAddOutlined} from "@ant-design/icons"; | |||
import * as Setting from "./Setting"; | |||
import * as FileBackend from "./backend/FileBackend"; | |||
import DocViewer, { DocViewerRenderers } from "react-doc-viewer"; | |||
import FileViewer from 'react-file-viewer'; | |||
import i18next from "i18next"; | |||
import * as PermissionUtil from "./PermissionUtil"; | |||
import {Controlled as CodeMirror} from "react-codemirror2"; | |||
import "codemirror/lib/codemirror.css"; | |||
@@ -286,10 +287,16 @@ class FileTree extends React.Component { | |||
okText="OK" | |||
cancelText="Cancel" | |||
> | |||
<Button icon={<DeleteOutlined />} size="small" /> | |||
<Button style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" /> | |||
</Popconfirm> | |||
</span> | |||
</Tooltip> | |||
<Tooltip title={i18next.t("store:Add Permission")}> | |||
<Button icon={<FileDoneOutlined />} size="small" onClick={(e) => { | |||
PermissionUtil.addPermission(this.props.account, this.props.store, file); | |||
e.stopPropagation(); | |||
}} /> | |||
</Tooltip> | |||
</div> | |||
}> | |||
{`${file.title} (${Setting.getFriendlyFileSize(file.size)})`} | |||
@@ -37,7 +37,7 @@ class FileTreePage extends React.Component { | |||
} | |||
return ( | |||
<FileTree store={this.state.store} /> | |||
<FileTree account={this.props.account} store={this.state.store} /> | |||
); | |||
} | |||
} | |||
@@ -36,7 +36,7 @@ class HomePage extends React.Component { | |||
} | |||
return ( | |||
<FileTree store={this.state.store} /> | |||
<FileTree account={this.props.account} store={this.state.store} /> | |||
); | |||
} | |||
} | |||
@@ -0,0 +1,34 @@ | |||
import * as PermissionBackend from "./backend/PermissionBackend"; | |||
import * as Setting from "./Setting"; | |||
import moment from "moment"; | |||
export function addPermission(account, store, file) { | |||
const randomName = Setting.getRandomName(); | |||
const newPermission = { | |||
owner: account.owner, | |||
name: `permission_${randomName}`, | |||
createdTime: moment().format(), | |||
displayName: `New Permission - ${randomName}`, | |||
users: [], | |||
roles: [], | |||
domains: [store.name], | |||
model: "Default", | |||
resourceType: "TreeNode", | |||
resources: [file.key], | |||
actions: ["Read"], | |||
effect: "Allow", | |||
isEnabled: true, | |||
submitter: account.name, | |||
approver: "", | |||
approveTime: "", | |||
state: "Pending", | |||
}; | |||
PermissionBackend.addPermission(newPermission) | |||
.then((res) => { | |||
Setting.openLink(Setting.getMyProfileUrl(account).replace("/account", `/permissions/${newPermission.owner}/${newPermission.name}`)); | |||
} | |||
) | |||
.catch(error => { | |||
Setting.showMessage("error", `Permission failed to add: ${error}`); | |||
}); | |||
} |
@@ -99,7 +99,7 @@ class StoreEditPage extends React.Component { | |||
{i18next.t("store:File tree")}: | |||
</Col> | |||
<Col span={22} > | |||
<FileTree store={this.state.store} /> | |||
<FileTree account={this.props.account} store={this.state.store} /> | |||
</Col> | |||
</Row> | |||
</Card> | |||
@@ -0,0 +1,49 @@ | |||
import * as Setting from "../Setting"; | |||
export function getGlobalPermissions() { | |||
return fetch(`${Setting.ServerUrl}/api/get-global-permissions`, { | |||
method: "GET", | |||
credentials: "include" | |||
}).then(res => res.json()); | |||
} | |||
export function getPermissions(owner) { | |||
return fetch(`${Setting.ServerUrl}/api/get-permissions?owner=${owner}`, { | |||
method: "GET", | |||
credentials: "include" | |||
}).then(res => res.json()); | |||
} | |||
export function getPermission(owner, name) { | |||
return fetch(`${Setting.ServerUrl}/api/get-permission?id=${owner}/${encodeURIComponent(name)}`, { | |||
method: "GET", | |||
credentials: "include" | |||
}).then(res => res.json()); | |||
} | |||
export function updatePermission(owner, name, permission) { | |||
let newPermission = Setting.deepCopy(permission); | |||
return fetch(`${Setting.ServerUrl}/api/update-permission?id=${owner}/${encodeURIComponent(name)}`, { | |||
method: 'POST', | |||
credentials: 'include', | |||
body: JSON.stringify(newPermission), | |||
}).then(res => res.json()); | |||
} | |||
export function addPermission(permission) { | |||
let newPermission = Setting.deepCopy(permission); | |||
return fetch(`${Setting.ServerUrl}/api/add-permission`, { | |||
method: 'POST', | |||
credentials: 'include', | |||
body: JSON.stringify(newPermission), | |||
}).then(res => res.json()); | |||
} | |||
export function deletePermission(permission) { | |||
let newPermission = Setting.deepCopy(permission); | |||
return fetch(`${Setting.ServerUrl}/api/delete-permission`, { | |||
method: 'POST', | |||
credentials: 'include', | |||
body: JSON.stringify(newPermission), | |||
}).then(res => res.json()); | |||
} |
@@ -18,6 +18,7 @@ | |||
"Loading...": "Loading...", | |||
"Name": "Name", | |||
"No.": "No.", | |||
"Permissions": "Permissions", | |||
"Preview": "Preview", | |||
"Result": "Result", | |||
"Save": "Save", | |||
@@ -29,6 +30,7 @@ | |||
"Wordsets": "Wordsets" | |||
}, | |||
"store": { | |||
"Add Permission": "Add Permission", | |||
"Bucket": "Bucket", | |||
"Delete": "Delete", | |||
"Domain": "Domain", | |||
@@ -18,6 +18,7 @@ | |||
"Loading...": "加载中...", | |||
"Name": "名称", | |||
"No.": "序号", | |||
"Permissions": "我的权限", | |||
"Preview": "预览", | |||
"Result": "结果", | |||
"Save": "保存", | |||
@@ -29,6 +30,7 @@ | |||
"Wordsets": "我的词汇集" | |||
}, | |||
"store": { | |||
"Add Permission": "添加权限", | |||
"Bucket": "Bucket", | |||
"Delete": "删除", | |||
"Domain": "域名", | |||
@@ -71,4 +73,4 @@ | |||
"Vectorset": "向量集", | |||
"Words": "词汇表" | |||
} | |||
} | |||
} |