Compare commits

...

60 Commits

Author SHA1 Message Date
891e8e21d8 feat: support Web3-Onboard provider (#2209)
* feat: add Web3-Onboard idp

* feat: update Web3-Onboard logo

* feat: update package.json

* feat: remove unused package

* feat: add yarn build param --max_old_space_size=4096

* feat: remove log

* feat: add Wallet configure

* feat: remove hardware wallets
2023-08-13 23:58:57 +08:00
80b0d26813 fix: synchronize update the syncers (#2201)
Signed-off-by: baihhh <2542274498@qq.com>
2023-08-13 22:30:57 +08:00
db4ac60bb6 feat: fix LDAP mobile field incorrect mapped (#2206) 2023-08-12 13:45:26 +08:00
33a922f026 Add custom HTTP SMS provider 2023-08-12 12:52:53 +08:00
9f65053d04 Improve i18n 2023-08-12 02:44:38 +08:00
be969e5efa Fix typo 2023-08-11 22:18:35 +08:00
9156bd426b ci: Show provider.displayName in signin button 2023-08-11 16:29:52 +08:00
fe4a4328aa feat: refactor code in InitApi() 2023-08-11 16:17:29 +08:00
9899022bcd fix: check enforcer should not be nil (#2199)
* fix: check enforcer should not be nil

* fix: check enforcer should not be nil

* Update user.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-08-11 12:31:49 +08:00
1a9d02be46 feat: use the casbin model to store relationships between users and groups (#2178)
* fix:reslove conflict

* fix: remove interface
2023-08-11 10:59:18 +08:00
eafaa135b4 Change builtInAvailableField back to 5 2023-08-11 02:45:11 +08:00
6746551447 Improve error message in InitEnforcer() 2023-08-11 02:36:29 +08:00
3cb46c3628 Add isKey to syncer's table 2023-08-09 00:33:04 +08:00
558bcf95d6 feat: save policy in adapter edit page (#2190)
* fix: save policy in adapter

* fix: disable edit for builtin adapter
2023-08-09 00:12:53 +08:00
bb937c30c1 Fix empty cert in getPaymentProvider() 2023-08-08 22:37:48 +08:00
8dfdf7f767 ci: add GoogleCloud and QiNiu in Storage (#2188)
* feat: add GoogleCloud and QiNiu in Storage

Signed-off-by: baihhh <2542274498@qq.com>

* Update qiniu_cloud.go

* Update storage.go

---------

Signed-off-by: baihhh <2542274498@qq.com>
Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-08-08 22:34:55 +08:00
62b2082e82 Add getUserOrganization() to user edit page 2023-08-08 21:58:27 +08:00
a1806439f8 Add UserPrincipalName and MemberOf to get-ldap-users API 2023-08-08 20:18:47 +08:00
01e58158b7 feat: Remove useless code 2023-08-08 19:16:55 +08:00
15427ad9d6 fix: fix add provider error (#2184) 2023-08-07 17:22:32 +08:00
d058f78dc6 fix: fix broken links (#2181) 2023-08-07 01:02:03 +08:00
fd9dbf8251 feat: add multiple SMS providers (#2182)
* feat: add amazon sns and azure acs provider

* feat: add msg91 sms provider

* feat: add infobip sms provider

* feat: add ucloud sms provider

* feat: add baidu cloud sms provider

* fix: fix logo and azure acs
2023-08-07 00:59:17 +08:00
3220a04fa9 fix: use org/groupName replace groupName (#2180) 2023-08-06 20:16:44 +08:00
f06a4990bd fix: rename in init.go (#2179)
* fix: rename in init.go

* fix: remove blank line

* fix: remove blank line

* Update init.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-08-06 13:07:30 +08:00
9df7de5f27 Improve menu icons 2023-08-05 18:00:24 +08:00
56c808c091 Improve menu 2023-08-05 17:41:35 +08:00
9fd2421564 Update @ant-design/cssinjs dependency to avoid build error 2023-08-04 01:22:57 +08:00
689d45c7fa feat: fix org name cannot be changed bug 2023-08-03 18:48:37 +08:00
c24343bd53 Fix XxxChangeTrigger() doesn't return error bug 2023-08-03 18:45:49 +08:00
979f43638d Change builtInAvailableField to 10 2023-08-03 18:17:15 +08:00
685a4514cd fix: revert adapter port vartype to int (#2174) 2023-08-03 09:35:16 +08:00
a05ca3af24 feat: use role ID to search in GetPermissionsAndRolesByUser() (#2170) 2023-08-02 20:58:06 +08:00
c6f301ff9e Support svg in downloadImage() 2023-07-31 20:23:28 +08:00
d7b2bcf288 feat: support payment cancel state (#2165) 2023-07-31 15:24:13 +08:00
67ac3d6d21 Fix typo 2023-07-31 15:23:44 +08:00
912d5c6a7f fix: support enforcerId parameter in Enforce API (#2164) 2023-07-31 00:20:53 +08:00
32fbb5b534 Support custom provider for storage API 2023-07-30 23:19:45 +08:00
21004f3009 Fix GetResources() missing items bug 2023-07-30 22:47:14 +08:00
463bacd53b Add GetDirectResources() 2023-07-30 22:01:10 +08:00
78dc660041 feat: support 3 more language (#2163)
Signed-off-by: baihhh <2542274498@qq.com>
2023-07-30 20:45:47 +08:00
2fb9674171 Fix file not exist panic in StaticFilter() 2023-07-30 19:03:21 +08:00
55c522d3b7 Improve provider type input box 2023-07-30 17:31:36 +08:00
f879170663 Remove AI related code 2023-07-30 14:39:27 +08:00
12e5d9b583 Remove adapter.file 2023-07-30 12:08:05 +08:00
eefa1e6df4 fix: fix paypal payment provider and refactor payment code (#2159)
* feat: support paypal payment provider

* feat: support paypal flow

* feat: use owner replace org for payment

* feat: update paypal logic

* feat: gofumpt

* feat: update payment

* fix: fix notify

* feat: delete log
2023-07-30 11:54:42 +08:00
026fb207b3 fix: remove model in adapter page (#2161) 2023-07-29 23:42:08 +08:00
ea10f8e615 feat: make hard-coded authz adapter editable, rename adapter to ormer (#2149)
* refactor: rename casbinAdapter to casdoorAdapter

* feat: add initEnforcer

* fix: router

* refactor: make hard-coded code configurable

* fix: data type

* feat: support sqlite3

* feat: disable delete and edit name for built in resources

* feat: optimize code

* fix: init

* fix: e2e

* fix: remove datasourcename

* fix: revert rename

* refactor: change all ORM's Adatper to Ormer

* refactor: name
2023-07-29 15:07:04 +08:00
74b058aa3f Fix sync-ldap-users() bug, brought by: 666ff48837 2023-07-29 13:14:55 +08:00
6c628d7893 Fix static path not changed bug in makeGzipResponse() 2023-07-29 12:23:48 +08:00
a38896e4d8 Improve swagger docs 2023-07-29 11:35:03 +08:00
5f054c4989 Fix product links 2023-07-28 15:08:45 +08:00
fb16d8cee6 fix: not set count of enforcers to the response (#2155) 2023-07-28 14:46:11 +08:00
5e4ba4f338 feat: add authorize button and defaultValue (#2152)
Signed-off-by: baihhh <2542274498@qq.com>
2023-07-27 23:55:35 +08:00
ca47af2ee1 Make post_logout_redirect_uri optional for logout 2023-07-27 23:26:30 +08:00
59da104463 fix: update ldap admin pwd only if changed (#2146)
* fix ldap pwd update

* fix: linter

* fix: simplify check
2023-07-27 17:49:15 +08:00
c5bb916651 fix: fix response data in PricingPage.js (#2143) 2023-07-27 10:46:31 +08:00
e98264f957 fix: application fails to call /api/get-resources (#2139)
just like other apis, resource.go.GetResources() no longer calls ApiController.RequireSignedInUser() to auth or check
2023-07-26 17:19:00 +08:00
6a952952a8 fix: unmask application for org admin (#2138)
* feat: unmask application with user admin

* Update application.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-07-26 17:17:49 +08:00
ba8a0f36be Support custom actions in permission edit page 2023-07-26 14:49:45 +08:00
b5e9084e5d feat: en/decodeURI in permission/role name (#2137) 2023-07-26 13:08:35 +08:00
167 changed files with 10746 additions and 5205 deletions

141
ai/ai.go
View File

@ -1,141 +0,0 @@
// 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 ai
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/sashabaranov/go-openai"
)
func queryAnswer(authToken string, question string, timeout int) (string, error) {
// fmt.Printf("Question: %s\n", question)
client := getProxyClientFromToken(authToken)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(2+timeout*2)*time.Second)
defer cancel()
resp, err := client.CreateChatCompletion(
ctx,
openai.ChatCompletionRequest{
Model: openai.GPT3Dot5Turbo,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleUser,
Content: question,
},
},
},
)
if err != nil {
return "", err
}
res := resp.Choices[0].Message.Content
res = strings.Trim(res, "\n")
// fmt.Printf("Answer: %s\n\n", res)
return res, nil
}
func QueryAnswerSafe(authToken string, question string) string {
var res string
var err error
for i := 0; i < 10; i++ {
res, err = queryAnswer(authToken, question, i)
if err != nil {
if i > 0 {
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
}
} else {
break
}
}
if err != nil {
panic(err)
}
return res
}
func QueryAnswerStream(authToken string, question string, writer io.Writer, builder *strings.Builder) error {
client := getProxyClientFromToken(authToken)
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
// https://platform.openai.com/tokenizer
// https://github.com/pkoukk/tiktoken-go#available-encodings
promptTokens, err := getTokenSize(openai.GPT3TextDavinci003, question)
if err != nil {
return err
}
// https://platform.openai.com/docs/models/gpt-3-5
maxTokens := 4097 - promptTokens
respStream, err := client.CreateCompletionStream(
ctx,
openai.CompletionRequest{
Model: openai.GPT3TextDavinci003,
Prompt: question,
MaxTokens: maxTokens,
Stream: true,
},
)
if err != nil {
return err
}
defer respStream.Close()
isLeadingReturn := true
for {
completion, streamErr := respStream.Recv()
if streamErr != nil {
if streamErr == io.EOF {
break
}
return streamErr
}
data := completion.Choices[0].Text
if isLeadingReturn && len(data) != 0 {
if strings.Count(data, "\n") == len(data) {
continue
} else {
isLeadingReturn = false
}
}
fmt.Printf("%s", data)
// Write the streamed data as Server-Sent Events
if _, err = fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
// Append the response to the strings.Builder
builder.WriteString(data)
}
return nil
}

View File

@ -1,42 +0,0 @@
// 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.
//go:build !skipCi
// +build !skipCi
package ai
import (
"testing"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
"github.com/sashabaranov/go-openai"
)
func TestRun(t *testing.T) {
object.InitConfig()
proxy.InitHttpClient()
text, err := queryAnswer("", "hi", 5)
if err != nil {
panic(err)
}
println(text)
}
func TestToken(t *testing.T) {
println(getTokenSize(openai.GPT3TextDavinci003, ""))
}

View File

@ -18,60 +18,21 @@ import (
"strings" "strings"
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
stringadapter "github.com/qiangmzsx/string-adapter/v2" stringadapter "github.com/qiangmzsx/string-adapter/v2"
) )
var Enforcer *casbin.Enforcer var Enforcer *casbin.Enforcer
func InitAuthz() { func InitApi() {
var err error e, err := object.GetInitializedEnforcer(util.GetId("built-in", "api-enforcer-built-in"))
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
driverName := conf.GetConfigString("driverName")
dataSourceName := conf.GetConfigRealDataSourceName(driverName)
a, err := xormadapter.NewAdapterWithTableName(driverName, dataSourceName, "casbin_rule", tableNamePrefix, true)
if err != nil {
panic(err)
}
modelText := `
[request_definition]
r = subOwner, subName, method, urlPath, objOwner, objName
[policy_definition]
p = subOwner, subName, method, urlPath, objOwner, objName
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
(r.subName == p.subName || p.subName == "*" || r.subName != "anonymous" && p.subName == "!anonymous") && \
(r.method == p.method || p.method == "*") && \
(r.urlPath == p.urlPath || p.urlPath == "*") && \
(r.objOwner == p.objOwner || p.objOwner == "*") && \
(r.objName == p.objName || p.objName == "*") || \
(r.subOwner == r.objOwner && r.subName == r.objName)
`
m, err := model.NewModelFromString(modelText)
if err != nil {
panic(err)
}
Enforcer, err = casbin.NewEnforcer(m, a)
if err != nil { if err != nil {
panic(err) panic(err)
} }
Enforcer = e.Enforcer
Enforcer.ClearPolicy() Enforcer.ClearPolicy()
// if len(Enforcer.GetPolicy()) == 0 { // if len(Enforcer.GetPolicy()) == 0 {

View File

@ -290,10 +290,11 @@ func (c *ApiController) Logout() {
c.ResponseOk(user, application.HomepageUrl) c.ResponseOk(user, application.HomepageUrl)
return return
} else { } else {
if redirectUri == "" { // "post_logout_redirect_uri" has been made optional, see: https://github.com/casdoor/casdoor/issues/2151
c.ResponseError(c.T("general:Missing parameter") + ": post_logout_redirect_uri") // if redirectUri == "" {
return // c.ResponseError(c.T("general:Missing parameter") + ": post_logout_redirect_uri")
} // return
// }
if accessToken == "" { if accessToken == "" {
c.ResponseError(c.T("general:Missing parameter") + ": id_token_hint") c.ResponseError(c.T("general:Missing parameter") + ": id_token_hint")
return return

View File

@ -23,14 +23,14 @@ import (
xormadapter "github.com/casdoor/xorm-adapter/v3" xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
// GetCasbinAdapters // GetAdapters
// @Title GetCasbinAdapters // @Title GetAdapters
// @Tag Adapter API // @Tag Adapter API
// @Description get adapters // @Description get adapters
// @Param owner query string true "The owner of adapters" // @Param owner query string true "The owner of adapters"
// @Success 200 {array} object.Adapter The Response object // @Success 200 {array} object.Adapter The Response object
// @router /get-adapters [get] // @router /get-adapters [get]
func (c *ApiController) GetCasbinAdapters() { func (c *ApiController) GetAdapters() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize") limit := c.Input().Get("pageSize")
page := c.Input().Get("p") page := c.Input().Get("p")
@ -40,7 +40,7 @@ func (c *ApiController) GetCasbinAdapters() {
sortOrder := c.Input().Get("sortOrder") sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" { if limit == "" || page == "" {
adapters, err := object.GetCasbinAdapters(owner) adapters, err := object.GetAdapters(owner)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -49,14 +49,14 @@ func (c *ApiController) GetCasbinAdapters() {
c.ResponseOk(adapters) c.ResponseOk(adapters)
} else { } else {
limit := util.ParseInt(limit) limit := util.ParseInt(limit)
count, err := object.GetCasbinAdapterCount(owner, field, value) count, err := object.GetAdapterCount(owner, field, value)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
paginator := pagination.SetPaginator(c.Ctx, limit, count) paginator := pagination.SetPaginator(c.Ctx, limit, count)
adapters, err := object.GetPaginationCasbinAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder) adapters, err := object.GetPaginationAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -66,17 +66,17 @@ func (c *ApiController) GetCasbinAdapters() {
} }
} }
// GetCasbinAdapter // GetAdapter
// @Title GetCasbinAdapter // @Title GetAdapter
// @Tag Adapter API // @Tag Adapter API
// @Description get adapter // @Description get adapter
// @Param id query string true "The id ( owner/name ) of the adapter" // @Param id query string true "The id ( owner/name ) of the adapter"
// @Success 200 {object} object.Adapter The Response object // @Success 200 {object} object.Adapter The Response object
// @router /get-adapter [get] // @router /get-adapter [get]
func (c *ApiController) GetCasbinAdapter() { func (c *ApiController) GetAdapter() {
id := c.Input().Get("id") id := c.Input().Get("id")
adapter, err := object.GetCasbinAdapter(id) adapter, err := object.GetAdapter(id)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -85,75 +85,75 @@ func (c *ApiController) GetCasbinAdapter() {
c.ResponseOk(adapter) c.ResponseOk(adapter)
} }
// UpdateCasbinAdapter // UpdateAdapter
// @Title UpdateCasbinAdapter // @Title UpdateAdapter
// @Tag Adapter API // @Tag Adapter API
// @Description update adapter // @Description update adapter
// @Param id query string true "The id ( owner/name ) of the adapter" // @Param id query string true "The id ( owner/name ) of the adapter"
// @Param body body object.Adapter true "The details of the adapter" // @Param body body object.Adapter true "The details of the adapter"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-adapter [post] // @router /update-adapter [post]
func (c *ApiController) UpdateCasbinAdapter() { func (c *ApiController) UpdateAdapter() {
id := c.Input().Get("id") id := c.Input().Get("id")
var casbinAdapter object.CasbinAdapter var adapter object.Adapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter) err := json.Unmarshal(c.Ctx.Input.RequestBody, &adapter)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
c.Data["json"] = wrapActionResponse(object.UpdateCasbinAdapter(id, &casbinAdapter)) c.Data["json"] = wrapActionResponse(object.UpdateAdapter(id, &adapter))
c.ServeJSON() c.ServeJSON()
} }
// AddCasbinAdapter // AddAdapter
// @Title AddCasbinAdapter // @Title AddAdapter
// @Tag Adapter API // @Tag Adapter API
// @Description add adapter // @Description add adapter
// @Param body body object.Adapter true "The details of the adapter" // @Param body body object.Adapter true "The details of the adapter"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /add-adapter [post] // @router /add-adapter [post]
func (c *ApiController) AddCasbinAdapter() { func (c *ApiController) AddAdapter() {
var casbinAdapter object.CasbinAdapter var adapter object.Adapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter) err := json.Unmarshal(c.Ctx.Input.RequestBody, &adapter)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
c.Data["json"] = wrapActionResponse(object.AddCasbinAdapter(&casbinAdapter)) c.Data["json"] = wrapActionResponse(object.AddAdapter(&adapter))
c.ServeJSON() c.ServeJSON()
} }
// DeleteCasbinAdapter // DeleteAdapter
// @Title DeleteCasbinAdapter // @Title DeleteAdapter
// @Tag Adapter API // @Tag Adapter API
// @Description delete adapter // @Description delete adapter
// @Param body body object.Adapter true "The details of the adapter" // @Param body body object.Adapter true "The details of the adapter"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /delete-adapter [post] // @router /delete-adapter [post]
func (c *ApiController) DeleteCasbinAdapter() { func (c *ApiController) DeleteAdapter() {
var casbinAdapter object.CasbinAdapter var adapter object.Adapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter) err := json.Unmarshal(c.Ctx.Input.RequestBody, &adapter)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
c.Data["json"] = wrapActionResponse(object.DeleteCasbinAdapter(&casbinAdapter)) c.Data["json"] = wrapActionResponse(object.DeleteAdapter(&adapter))
c.ServeJSON() c.ServeJSON()
} }
func (c *ApiController) SyncPolicies() { func (c *ApiController) GetPolicies() {
id := c.Input().Get("id") id := c.Input().Get("id")
adapter, err := object.GetCasbinAdapter(id) adapter, err := object.GetAdapter(id)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
policies, err := object.SyncPolicies(adapter) policies, err := object.GetPolicies(adapter)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -164,7 +164,7 @@ func (c *ApiController) SyncPolicies() {
func (c *ApiController) UpdatePolicy() { func (c *ApiController) UpdatePolicy() {
id := c.Input().Get("id") id := c.Input().Get("id")
adapter, err := object.GetCasbinAdapter(id) adapter, err := object.GetAdapter(id)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -188,7 +188,7 @@ func (c *ApiController) UpdatePolicy() {
func (c *ApiController) AddPolicy() { func (c *ApiController) AddPolicy() {
id := c.Input().Get("id") id := c.Input().Get("id")
adapter, err := object.GetCasbinAdapter(id) adapter, err := object.GetAdapter(id)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -212,7 +212,7 @@ func (c *ApiController) AddPolicy() {
func (c *ApiController) RemovePolicy() { func (c *ApiController) RemovePolicy() {
id := c.Input().Get("id") id := c.Input().Get("id")
adapter, err := object.GetCasbinAdapter(id) adapter, err := object.GetAdapter(id)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return

View File

@ -35,6 +35,7 @@ func (c *ApiController) Enforce() {
permissionId := c.Input().Get("permissionId") permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId") modelId := c.Input().Get("modelId")
resourceId := c.Input().Get("resourceId") resourceId := c.Input().Get("resourceId")
enforcerId := c.Input().Get("enforcerId")
var request object.CasbinRequest var request object.CasbinRequest
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request) err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
@ -43,6 +44,23 @@ func (c *ApiController) Enforce() {
return return
} }
if enforcerId != "" {
enforcer, err := object.GetInitializedEnforcer(enforcerId)
if err != nil {
c.ResponseError(err.Error())
return
}
res, err := enforcer.Enforce(request...)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
return
}
if permissionId != "" { if permissionId != "" {
permission, err := object.GetPermission(permissionId) permission, err := object.GetPermission(permissionId)
if err != nil { if err != nil {
@ -121,6 +139,7 @@ func (c *ApiController) Enforce() {
func (c *ApiController) BatchEnforce() { func (c *ApiController) BatchEnforce() {
permissionId := c.Input().Get("permissionId") permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId") modelId := c.Input().Get("modelId")
enforcerId := c.Input().Get("enforcerId")
var requests []object.CasbinRequest var requests []object.CasbinRequest
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests) err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
@ -129,6 +148,23 @@ func (c *ApiController) BatchEnforce() {
return return
} }
if enforcerId != "" {
enforcer, err := object.GetInitializedEnforcer(enforcerId)
if err != nil {
c.ResponseError(err.Error())
return
}
res, err := enforcer.BatchEnforce(requests)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
return
}
if permissionId != "" { if permissionId != "" {
permission, err := object.GetPermission(permissionId) permission, err := object.GetPermission(permissionId)
if err != nil { if err != nil {

View File

@ -1,145 +0,0 @@
// 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 controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetChats
// @Title GetChats
// @Tag Chat API
// @Description get chats
// @Param owner query string true "The owner of chats"
// @Success 200 {array} object.Chat The Response object
// @router /get-chats [get]
func (c *ApiController) GetChats() {
owner := "admin"
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
maskedChats, err := object.GetMaskedChats(object.GetChats(owner))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedChats)
} else {
limit := util.ParseInt(limit)
count, err := object.GetChatCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
chats, err := object.GetMaskedChats(object.GetPaginationChats(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(chats, paginator.Nums())
}
}
// GetChat
// @Title GetChat
// @Tag Chat API
// @Description get chat
// @Param id query string true "The id ( owner/name ) of the chat"
// @Success 200 {object} object.Chat The Response object
// @router /get-chat [get]
func (c *ApiController) GetChat() {
id := c.Input().Get("id")
maskedChat, err := object.GetMaskedChat(object.GetChat(id))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedChat)
}
// UpdateChat
// @Title UpdateChat
// @Tag Chat API
// @Description update chat
// @Param id query string true "The id ( owner/name ) of the chat"
// @Param body body object.Chat true "The details of the chat"
// @Success 200 {object} controllers.Response The Response object
// @router /update-chat [post]
func (c *ApiController) UpdateChat() {
id := c.Input().Get("id")
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateChat(id, &chat))
c.ServeJSON()
}
// AddChat
// @Title AddChat
// @Tag Chat API
// @Description add chat
// @Param body body object.Chat true "The details of the chat"
// @Success 200 {object} controllers.Response The Response object
// @router /add-chat [post]
func (c *ApiController) AddChat() {
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddChat(&chat))
c.ServeJSON()
}
// DeleteChat
// @Title DeleteChat
// @Tag Chat API
// @Description delete chat
// @Param body body object.Chat true "The details of the chat"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-chat [post]
func (c *ApiController) DeleteChat() {
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteChat(&chat))
c.ServeJSON()
}

View File

@ -61,7 +61,7 @@ func (c *ApiController) GetEnforcers() {
return return
} }
c.ResponseOk(enforcers) c.ResponseOk(enforcers, paginator.Nums())
} }
} }

View File

@ -1,313 +0,0 @@
// 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 controllers
import (
"encoding/json"
"fmt"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/ai"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetMessages
// @Title GetMessages
// @Tag Message API
// @Description get messages
// @Param owner query string true "The owner of messages"
// @Success 200 {array} object.Message The Response object
// @router /get-messages [get]
func (c *ApiController) GetMessages() {
owner := c.Input().Get("owner")
organization := c.Input().Get("organization")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
chat := c.Input().Get("chat")
if limit == "" || page == "" {
var messages []*object.Message
var err error
if chat == "" {
messages, err = object.GetMessages(owner)
} else {
messages, err = object.GetChatMessages(chat)
}
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedMessages(messages))
} else {
limit := util.ParseInt(limit)
count, err := object.GetMessageCount(owner, organization, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginationMessages, err := object.GetPaginationMessages(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
messages := object.GetMaskedMessages(paginationMessages)
c.ResponseOk(messages, paginator.Nums())
}
}
// GetMessage
// @Title GetMessage
// @Tag Message API
// @Description get message
// @Param id query string true "The id ( owner/name ) of the message"
// @Success 200 {object} object.Message The Response object
// @router /get-message [get]
func (c *ApiController) GetMessage() {
id := c.Input().Get("id")
message, err := object.GetMessage(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(message)
}
func (c *ApiController) ResponseErrorStream(errorText string) {
event := fmt.Sprintf("event: myerror\ndata: %s\n\n", errorText)
_, err := c.Ctx.ResponseWriter.Write([]byte(event))
if err != nil {
c.ResponseError(err.Error())
return
}
}
// GetMessageAnswer
// @Title GetMessageAnswer
// @Tag Message API
// @Description get message answer
// @Param id query string true "The id ( owner/name ) of the message"
// @Success 200 {object} object.Message The Response object
// @router /get-message-answer [get]
func (c *ApiController) GetMessageAnswer() {
id := c.Input().Get("id")
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
message, err := object.GetMessage(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if message == nil {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id))
return
}
if message.Author != "AI" || message.ReplyTo == "" || message.Text != "" {
c.ResponseErrorStream(c.T("chat:The message is invalid"))
return
}
chatId := util.GetId("admin", message.Chat)
chat, err := object.GetChat(chatId)
if err != nil {
c.ResponseError(err.Error())
return
}
if chat == nil || chat.Organization != message.Organization {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId))
return
}
if chat.Type != "AI" {
c.ResponseErrorStream(c.T("chat:The chat type must be \"AI\""))
return
}
questionMessage, err := object.GetMessage(message.ReplyTo)
if questionMessage == nil {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id))
return
}
providerId := util.GetId(chat.Owner, chat.User2)
provider, err := object.GetProvider(providerId)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is not found"), providerId))
return
}
if provider.Category != "AI" || provider.ClientSecret == "" {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is invalid"), providerId))
return
}
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
authToken := provider.ClientSecret
question := questionMessage.Text
var stringBuilder strings.Builder
fmt.Printf("Question: [%s]\n", questionMessage.Text)
fmt.Printf("Answer: [")
err = ai.QueryAnswerStream(authToken, question, c.Ctx.ResponseWriter, &stringBuilder)
if err != nil {
c.ResponseErrorStream(err.Error())
return
}
fmt.Printf("]\n")
event := fmt.Sprintf("event: end\ndata: %s\n\n", "end")
_, err = c.Ctx.ResponseWriter.Write([]byte(event))
if err != nil {
c.ResponseError(err.Error())
return
}
answer := stringBuilder.String()
message.Text = answer
_, err = object.UpdateMessage(message.GetId(), message)
if err != nil {
c.ResponseError(err.Error())
return
}
}
// UpdateMessage
// @Title UpdateMessage
// @Tag Message API
// @Description update message
// @Param id query string true "The id ( owner/name ) of the message"
// @Param body body object.Message true "The details of the message"
// @Success 200 {object} controllers.Response The Response object
// @router /update-message [post]
func (c *ApiController) UpdateMessage() {
id := c.Input().Get("id")
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateMessage(id, &message))
c.ServeJSON()
}
// AddMessage
// @Title AddMessage
// @Tag Message API
// @Description add message
// @Param body body object.Message true "The details of the message"
// @Success 200 {object} controllers.Response The Response object
// @router /add-message [post]
func (c *ApiController) AddMessage() {
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
var chat *object.Chat
if message.Chat != "" {
chatId := util.GetId("admin", message.Chat)
chat, err = object.GetChat(chatId)
if err != nil {
c.ResponseError(err.Error())
return
}
if chat == nil || chat.Organization != message.Organization {
c.ResponseError(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId))
return
}
}
affected, err := object.AddMessage(&message)
if err != nil {
c.ResponseError(err.Error())
return
}
if affected {
if chat != nil && chat.Type == "AI" {
answerMessage := &object.Message{
Owner: message.Owner,
Name: fmt.Sprintf("message_%s", util.GetRandomName()),
CreatedTime: util.GetCurrentTimeEx(message.CreatedTime),
Organization: message.Organization,
Chat: message.Chat,
ReplyTo: message.GetId(),
Author: "AI",
Text: "",
}
_, err = object.AddMessage(answerMessage)
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}
// DeleteMessage
// @Title DeleteMessage
// @Tag Message API
// @Description delete message
// @Param body body object.Message true "The details of the message"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-message [post]
func (c *ApiController) DeleteMessage() {
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteMessage(&message))
c.ServeJSON()
}

View File

@ -31,7 +31,6 @@ import (
// @router /get-payments [get] // @router /get-payments [get]
func (c *ApiController) GetPayments() { func (c *ApiController) GetPayments() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
organization := c.Input().Get("organization")
limit := c.Input().Get("pageSize") limit := c.Input().Get("pageSize")
page := c.Input().Get("p") page := c.Input().Get("p")
field := c.Input().Get("field") field := c.Input().Get("field")
@ -49,14 +48,14 @@ func (c *ApiController) GetPayments() {
c.ResponseOk(payments) c.ResponseOk(payments)
} else { } else {
limit := util.ParseInt(limit) limit := util.ParseInt(limit)
count, err := object.GetPaymentCount(owner, organization, field, value) count, err := object.GetPaymentCount(owner, field, value)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
paginator := pagination.SetPaginator(c.Ctx, limit, count) paginator := pagination.SetPaginator(c.Ctx, limit, count)
payments, err := object.GetPaginationPayments(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder) payments, err := object.GetPaginationPayments(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -77,10 +76,9 @@ func (c *ApiController) GetPayments() {
// @router /get-user-payments [get] // @router /get-user-payments [get]
func (c *ApiController) GetUserPayments() { func (c *ApiController) GetUserPayments() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
organization := c.Input().Get("organization")
user := c.Input().Get("user") user := c.Input().Get("user")
payments, err := object.GetUserPayments(owner, organization, user) payments, err := object.GetUserPayments(owner, user)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -177,24 +175,18 @@ func (c *ApiController) DeletePayment() {
// @router /notify-payment [post] // @router /notify-payment [post]
func (c *ApiController) NotifyPayment() { func (c *ApiController) NotifyPayment() {
owner := c.Ctx.Input.Param(":owner") owner := c.Ctx.Input.Param(":owner")
providerName := c.Ctx.Input.Param(":provider")
productName := c.Ctx.Input.Param(":product")
paymentName := c.Ctx.Input.Param(":payment") paymentName := c.Ctx.Input.Param(":payment")
orderId := c.Ctx.Input.Param("order") orderId := c.Ctx.Input.Param("order")
body := c.Ctx.Input.RequestBody body := c.Ctx.Input.RequestBody
err, errorResponse := object.NotifyPayment(c.Ctx.Request, body, owner, providerName, productName, paymentName, orderId) payment, err := object.NotifyPayment(c.Ctx.Request, body, owner, paymentName, orderId)
_, err2 := c.Ctx.ResponseWriter.Write([]byte(errorResponse))
if err2 != nil {
panic(err2)
}
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
c.ResponseOk(payment)
} }
// InvoicePayment // InvoicePayment

View File

@ -52,15 +52,22 @@ func (c *ApiController) GetResources() {
sortField := c.Input().Get("sortField") sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder") sortOrder := c.Input().Get("sortOrder")
userObj, ok := c.RequireSignedInUser() if sortField == "Direct" {
if !ok { provider, err := c.GetProviderFromContext("Storage")
if err != nil {
c.ResponseError(err.Error())
return return
} }
if userObj.IsAdmin {
user = "" prefix := sortOrder
resources, err := object.GetDirectResources(owner, user, provider, prefix, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
} }
if limit == "" || page == "" { c.ResponseOk(resources)
} else if limit == "" || page == "" {
resources, err := object.GetResources(owner, user) resources, err := object.GetResources(owner, user)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
@ -160,11 +167,16 @@ func (c *ApiController) DeleteResource() {
return return
} }
if resource.Provider != "" {
c.Input().Set("provider", resource.Provider)
}
c.Input().Set("fullFilePath", resource.Name)
provider, err := c.GetProviderFromContext("Storage") provider, err := c.GetProviderFromContext("Storage")
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
_, resource.Name = refineFullFilePath(resource.Name)
err = object.DeleteFile(provider, resource.Name, c.GetAcceptLanguage()) err = object.DeleteFile(provider, resource.Name, c.GetAcceptLanguage())
if err != nil { if err != nil {
@ -224,6 +236,7 @@ func (c *ApiController) UploadResource() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
_, fullFilePath = refineFullFilePath(fullFilePath)
fileType := "unknown" fileType := "unknown"
contentType := header.Header.Get("Content-Type") contentType := header.Header.Get("Content-Type")

View File

@ -140,11 +140,13 @@ func (c *ApiController) SendSms() {
return return
} }
if provider.Type != "Custom HTTP SMS" {
invalidReceivers := getInvalidSmsReceivers(smsForm) invalidReceivers := getInvalidSmsReceivers(smsForm)
if len(invalidReceivers) != 0 { if len(invalidReceivers) != 0 {
c.ResponseError(fmt.Sprintf(c.T("service:Invalid phone receivers: %s"), strings.Join(invalidReceivers, ", "))) c.ResponseError(fmt.Sprintf(c.T("service:Invalid phone receivers: %s"), strings.Join(invalidReceivers, ", ")))
return return
} }
}
err = object.SendSms(provider, smsForm.Content, smsForm.Receivers...) err = object.SendSms(provider, smsForm.Content, smsForm.Receivers...)
if err != nil { if err != nil {

View File

@ -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)
} }

View File

@ -16,6 +16,7 @@ package controllers
import ( import (
"fmt" "fmt"
"strings"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
@ -143,8 +144,30 @@ func (c *ApiController) IsMaskedEnabled() (bool, bool) {
return true, isMaskEnabled return true, isMaskEnabled
} }
func refineFullFilePath(fullFilePath string) (string, string) {
tokens := strings.Split(fullFilePath, "/")
if len(tokens) >= 2 && tokens[0] == "Direct" && tokens[1] != "" {
providerName := tokens[1]
res := strings.Join(tokens[2:], "/")
return providerName, "/" + res
} else {
return "", fullFilePath
}
}
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, error) { func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, error) {
providerName := c.Input().Get("provider") providerName := c.Input().Get("provider")
if providerName == "" {
field := c.Input().Get("field")
value := c.Input().Get("value")
if field == "provider" && value != "" {
providerName = value
} else {
fullFilePath := c.Input().Get("fullFilePath")
providerName, _ = refineFullFilePath(fullFilePath)
}
}
if providerName != "" { if providerName != "" {
provider, err := object.GetProvider(util.GetId("admin", providerName)) provider, err := object.GetProvider(util.GetId("admin", providerName))
if err != nil { if err != nil {

View File

@ -26,9 +26,10 @@ import (
// @Title GetWebhooks // @Title GetWebhooks
// @Tag Webhook API // @Tag Webhook API
// @Description get webhooks // @Description get webhooks
// @Param owner query string true "The owner of webhooks" // @Param owner query string built-in/admin true "The owner of webhooks"
// @Success 200 {array} object.Webhook The Response object // @Success 200 {array} object.Webhook The Response object
// @router /get-webhooks [get] // @router /get-webhooks [get]
// @Security test_apiKey
func (c *ApiController) GetWebhooks() { func (c *ApiController) GetWebhooks() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize") limit := c.Input().Get("pageSize")
@ -71,7 +72,7 @@ func (c *ApiController) GetWebhooks() {
// @Title GetWebhook // @Title GetWebhook
// @Tag Webhook API // @Tag Webhook API
// @Description get webhook // @Description get webhook
// @Param id query string true "The id ( owner/name ) of the webhook" // @Param id query string built-in/admin true "The id ( owner/name ) of the webhook"
// @Success 200 {object} object.Webhook The Response object // @Success 200 {object} object.Webhook The Response object
// @router /get-webhook [get] // @router /get-webhook [get]
func (c *ApiController) GetWebhook() { func (c *ApiController) GetWebhook() {
@ -90,7 +91,7 @@ func (c *ApiController) GetWebhook() {
// @Title UpdateWebhook // @Title UpdateWebhook
// @Tag Webhook API // @Tag Webhook API
// @Description update webhook // @Description update webhook
// @Param id query string true "The id ( owner/name ) of the webhook" // @Param id query string built-in/admin true "The id ( owner/name ) of the webhook"
// @Param body body object.Webhook true "The details of the webhook" // @Param body body object.Webhook true "The details of the webhook"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-webhook [post] // @router /update-webhook [post]

23
go.mod
View File

@ -12,13 +12,12 @@ 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.0 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
github.com/dlclark/regexp2 v1.9.0 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/fogleman/gg v1.3.0 github.com/fogleman/gg v1.3.0
github.com/forestmgy/ldapserver v1.1.0 github.com/forestmgy/ldapserver v1.1.0
@ -29,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
@ -42,21 +38,19 @@ require (
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nyaruka/phonenumbers v1.1.5 github.com/nyaruka/phonenumbers v1.1.5
github.com/pkoukk/tiktoken-go v0.1.1
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
github.com/russellhaering/goxmldsig v1.2.0 github.com/russellhaering/goxmldsig v1.2.0
github.com/sashabaranov/go-openai v1.12.0
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
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
@ -64,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
) )

1427
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,9 @@ func TestGenerateI18nFrontend(t *testing.T) {
applyToOtherLanguage("frontend", "ru", data) applyToOtherLanguage("frontend", "ru", data)
applyToOtherLanguage("frontend", "vi", data) applyToOtherLanguage("frontend", "vi", data)
applyToOtherLanguage("frontend", "pt", data) applyToOtherLanguage("frontend", "pt", data)
applyToOtherLanguage("frontend", "it", data)
applyToOtherLanguage("frontend", "ms", data)
applyToOtherLanguage("frontend", "tr", data)
} }
func TestGenerateI18nBackend(t *testing.T) { func TestGenerateI18nBackend(t *testing.T) {
@ -49,4 +52,7 @@ func TestGenerateI18nBackend(t *testing.T) {
applyToOtherLanguage("backend", "ru", data) applyToOtherLanguage("backend", "ru", data)
applyToOtherLanguage("backend", "vi", data) applyToOtherLanguage("backend", "vi", data)
applyToOtherLanguage("backend", "pt", data) applyToOtherLanguage("backend", "pt", data)
applyToOtherLanguage("backend", "it", data)
applyToOtherLanguage("backend", "ms", data)
applyToOtherLanguage("backend", "tr", data)
} }

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein" "Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein", "Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein", "DisplayName cannot be blank": "Anzeigename kann nicht leer sein",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Service %s and %s do not match" "Service %s and %s do not match": "Service %s and %s do not match"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Affiliation cannot be blank", "Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank", "DisplayName cannot be blank": "DisplayName cannot be blank",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Los servicios %s y %s no coinciden" "Service %s and %s do not match": "Los servicios %s y %s no coinciden"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Afiliación no puede estar en blanco", "Affiliation cannot be blank": "Afiliación no puede estar en blanco",
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco", "DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas" "Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Affiliation ne peut pas être vide", "Affiliation cannot be blank": "Affiliation ne peut pas être vide",
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide", "DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok" "Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong", "Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong", "DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",

150
i18n/locales/it/data.json Normal file
View File

@ -0,0 +1,150 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "サービス%sと%sは一致しません" "Service %s and %s do not match": "サービス%sと%sは一致しません"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "所属は空白にできません", "Affiliation cannot be blank": "所属は空白にできません",
"DisplayName cannot be blank": "表示名は空白にできません", "DisplayName cannot be blank": "表示名は空白にできません",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다" "Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다", "Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다", "DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",

150
i18n/locales/ms/data.json Normal file
View File

@ -0,0 +1,150 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Service %s and %s do not match" "Service %s and %s do not match": "Service %s and %s do not match"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Affiliation cannot be blank", "Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank", "DisplayName cannot be blank": "DisplayName cannot be blank",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Сервисы %s и %s не совпадают" "Service %s and %s do not match": "Сервисы %s и %s не совпадают"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Принадлежность не может быть пустым значением", "Affiliation cannot be blank": "Принадлежность не может быть пустым значением",
"DisplayName cannot be blank": "Имя отображения не может быть пустым", "DisplayName cannot be blank": "Имя отображения не может быть пустым",

150
i18n/locales/tr/data.json Normal file
View File

@ -0,0 +1,150 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp" "Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "Tình trạng liên kết không thể để trống", "Affiliation cannot be blank": "Tình trạng liên kết không thể để trống",
"DisplayName cannot be blank": "Tên hiển thị không thể để trống", "DisplayName cannot be blank": "Tên hiển thị không thể để trống",

View File

@ -24,14 +24,6 @@
"cas": { "cas": {
"Service %s and %s do not match": "服务%s与%s不匹配" "Service %s and %s do not match": "服务%s与%s不匹配"
}, },
"chat": {
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
"The chat: %s is not found": "The chat: %s is not found",
"The message is invalid": "The message is invalid",
"The message: %s is not found": "The message: %s is not found",
"The provider: %s is invalid": "The provider: %s is invalid",
"The provider: %s is not found": "The provider: %s is not found"
},
"check": { "check": {
"Affiliation cannot be blank": "工作单位不可为空", "Affiliation cannot be blank": "工作单位不可为空",
"DisplayName cannot be blank": "显示名称不可为空", "DisplayName cannot be blank": "显示名称不可为空",

View File

@ -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,

View File

@ -24,20 +24,10 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
const Web3AuthTokenKey = "web3AuthToken"
type MetaMaskIdProvider struct { type MetaMaskIdProvider struct {
Client *http.Client Client *http.Client
} }
type Web3AuthToken struct {
Address string `json:"address"`
Nonce string `json:"nonce"`
CreateAt uint64 `json:"createAt"`
TypedData string `json:"typedData"`
Signature string `json:"signature"` // signature for typed data
}
func NewMetaMaskIdProvider() *MetaMaskIdProvider { func NewMetaMaskIdProvider() *MetaMaskIdProvider {
idp := &MetaMaskIdProvider{} idp := &MetaMaskIdProvider{}
return idp return idp

View File

@ -111,6 +111,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl) return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
case "MetaMask": case "MetaMask":
return NewMetaMaskIdProvider() return NewMetaMaskIdProvider()
case "Web3Onboard":
return NewWeb3OnboardIdProvider()
default: default:
if isGothSupport(idpInfo.Type) { if isGothSupport(idpInfo.Type) {
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl) return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)

103
idp/web3onboard.go Normal file
View File

@ -0,0 +1,103 @@
// 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 idp
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
"golang.org/x/oauth2"
)
const Web3AuthTokenKey = "web3AuthToken"
type Web3AuthToken struct {
Address string `json:"address"`
Nonce string `json:"nonce"`
CreateAt uint64 `json:"createAt"`
TypedData string `json:"typedData"` // typed data use for application
Signature string `json:"signature"` // signature for typed data
WalletType string `json:"walletType"` // e.g."MetaMask", "Coinbase"
}
type Web3OnboardIdProvider struct {
Client *http.Client
}
func NewWeb3OnboardIdProvider() *Web3OnboardIdProvider {
idp := &Web3OnboardIdProvider{}
return idp
}
func (idp *Web3OnboardIdProvider) SetHttpClient(client *http.Client) {
idp.Client = client
}
func (idp *Web3OnboardIdProvider) GetToken(code string) (*oauth2.Token, error) {
web3AuthToken := Web3AuthToken{}
if err := json.Unmarshal([]byte(code), &web3AuthToken); err != nil {
return nil, err
}
token := &oauth2.Token{
AccessToken: fmt.Sprintf("%v:%v", Web3AuthTokenKey, web3AuthToken.Address),
TokenType: "Bearer",
Expiry: time.Now().AddDate(0, 1, 0),
}
token = token.WithExtra(map[string]interface{}{
Web3AuthTokenKey: web3AuthToken,
})
return token, nil
}
func (idp *Web3OnboardIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
web3AuthToken, ok := token.Extra(Web3AuthTokenKey).(Web3AuthToken)
if !ok {
return nil, errors.New("invalid web3AuthToken")
}
fmtAddress := fmt.Sprintf("%v_%v",
strings.ReplaceAll(strings.TrimSpace(web3AuthToken.WalletType), " ", "_"),
web3AuthToken.Address,
)
userInfo := &UserInfo{
Id: fmtAddress,
Username: fmtAddress,
DisplayName: fmtAddress,
AvatarUrl: fmt.Sprintf("metamask:%v", forceEthereumAddress(web3AuthToken.Address)),
}
return userInfo, nil
}
func forceEthereumAddress(address string) string {
// The required address to general MetaMask avatar is a string of length 42 that represents an Ethereum address.
// This function is used to force any address as an Ethereum address
address = strings.TrimSpace(address)
var builder strings.Builder
for _, ch := range address {
builder.WriteRune(ch)
}
for len(builder.String()) < 42 {
builder.WriteString("0")
}
if len(builder.String()) > 42 {
return builder.String()[:42]
}
return builder.String()
}

View File

@ -9,11 +9,11 @@
"passwordType": "plain", "passwordType": "plain",
"passwordSalt": "", "passwordSalt": "",
"passwordOptions": ["AtLeast6"], "passwordOptions": ["AtLeast6"],
"countryCodes": ["US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN"], "countryCodes": ["US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR"],
"defaultAvatar": "", "defaultAvatar": "",
"defaultApplication": "", "defaultApplication": "",
"tags": [], "tags": [],
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi"], "languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr"],
"masterPassword": "", "masterPassword": "",
"initScore": 2000, "initScore": 2000,
"enableSoftDeletion": false, "enableSoftDeletion": false,

View File

@ -48,7 +48,8 @@ func main() {
object.InitDefaultStorageProvider() object.InitDefaultStorageProvider()
object.InitLdapAutoSynchronizer() object.InitLdapAutoSynchronizer()
proxy.InitHttpClient() proxy.InitHttpClient()
authz.InitAuthz() authz.InitApi()
object.InitUserManager()
util.SafeGoroutine(func() { object.RunSyncUsersJob() }) util.SafeGoroutine(func() { object.RunSyncUsersJob() })
@ -62,7 +63,7 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage) beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved. // Copyright 2022 The Casdoor Authors. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,365 +15,329 @@
package object package object
import ( import (
"database/sql"
"fmt" "fmt"
"runtime"
"strings" "strings"
"github.com/beego/beego" "github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"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/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
"github.com/xorm-io/core" "github.com/xorm-io/core"
"github.com/xorm-io/xorm" "github.com/xorm-io/xorm"
_ "modernc.org/sqlite" // db = sqlite
) )
var adapter *Adapter
func InitConfig() {
err := beego.LoadAppConfig("ini", "../conf/app.conf")
if err != nil {
panic(err)
}
beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true)
CreateTables(true)
DoMigration()
}
func InitAdapter(createDatabase bool) {
if createDatabase {
err := createDatabaseForPostgres(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
if err != nil {
panic(err)
}
}
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
adapter.Engine.SetTableMapper(tbMapper)
}
func CreateTables(createDatabase bool) {
if createDatabase {
err := adapter.CreateDatabase()
if err != nil {
panic(err)
}
}
adapter.createTable()
}
// Adapter represents the MySQL adapter for policy storage.
type Adapter struct { type Adapter struct {
driverName string Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
dataSourceName string Name string `xorm:"varchar(100) notnull pk" json:"name"`
dbName string CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
Engine *xorm.Engine
Type string `xorm:"varchar(100)" json:"type"`
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
User string `xorm:"varchar(100)" json:"user"`
Password string `xorm:"varchar(100)" json:"password"`
Database string `xorm:"varchar(100)" json:"database"`
Table string `xorm:"varchar(100)" json:"table"`
TableNamePrefix string `xorm:"varchar(100)" json:"tableNamePrefix"`
IsEnabled bool `json:"isEnabled"`
*xormadapter.Adapter `xorm:"-" json:"-"`
} }
// finalizer is the destructor for Adapter. func GetAdapterCount(owner, field, value string) (int64, error) {
func finalizer(a *Adapter) { session := GetSession(owner, -1, -1, field, value, "", "")
err := a.Engine.Close() return session.Count(&Adapter{})
}
func GetAdapters(owner string) ([]*Adapter, error) {
adapters := []*Adapter{}
err := ormer.Engine.Desc("created_time").Find(&adapters, &Adapter{Owner: owner})
if err != nil { if err != nil {
panic(err) return adapters, err
}
} }
// NewAdapter is the constructor for Adapter. return adapters, nil
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 createDatabaseForPostgres(driverName string, dataSourceName string, dbName string) error { func GetPaginationAdapters(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Adapter, error) {
if driverName == "postgres" { adapters := []*Adapter{}
db, err := sql.Open(driverName, dataSourceName) session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&adapters)
if err != nil { if err != nil {
return err return adapters, err
} }
defer db.Close()
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s;", dbName)) return adapters, nil
}
func getAdapter(owner, name string) (*Adapter, error) {
if owner == "" || name == "" {
return nil, nil
}
adapter := Adapter{Owner: owner, Name: name}
existed, err := ormer.Engine.Get(&adapter)
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "already exists") { return nil, err
return err
}
} }
return nil if existed {
return &adapter, nil
} else { } else {
return nil return nil, nil
} }
} }
func (a *Adapter) CreateDatabase() error { func GetAdapter(id string) (*Adapter, error) {
if a.driverName == "postgres" { owner, name := util.GetOwnerAndNameFromId(id)
return getAdapter(owner, name)
}
func UpdateAdapter(id string, adapter *Adapter) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if adapter, err := getAdapter(owner, name); adapter == nil {
return false, err
}
if name != adapter.Name {
err := adapterChangeTrigger(name, adapter.Name)
if err != nil {
return false, err
}
}
session := ormer.Engine.ID(core.PK{owner, name}).AllCols()
if adapter.Password == "***" {
session.Omit("password")
}
affected, err := session.Update(adapter)
if err != nil {
return false, err
}
return affected != 0, nil
}
func AddAdapter(adapter *Adapter) (bool, error) {
affected, err := ormer.Engine.Insert(adapter)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteAdapter(adapter *Adapter) (bool, error) {
affected, err := ormer.Engine.ID(core.PK{adapter.Owner, adapter.Name}).Delete(&Adapter{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (adapter *Adapter) GetId() string {
return fmt.Sprintf("%s/%s", adapter.Owner, adapter.Name)
}
func (adapter *Adapter) getTable() string {
if adapter.DatabaseType == "mssql" {
return fmt.Sprintf("[%s]", adapter.Table)
} else {
return adapter.Table
}
}
func (adapter *Adapter) initAdapter() error {
if adapter.Adapter == nil {
var dataSourceName string
if adapter.builtInAdapter() {
dataSourceName = conf.GetConfigString("dataSourceName")
if adapter.DatabaseType == "mysql" {
dataSourceName = dataSourceName + adapter.Database
}
} else {
switch adapter.DatabaseType {
case "mssql":
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", adapter.User,
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
case "mysql":
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", adapter.User,
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
case "postgres":
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)
case "CockroachDB":
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)
case "sqlite3":
dataSourceName = fmt.Sprintf("file:%s", adapter.Host)
default:
return fmt.Errorf("unsupported database type: %s", adapter.DatabaseType)
}
}
if !isCloudIntranet {
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
}
var err error
engine, err := xorm.NewEngine(adapter.DatabaseType, dataSourceName)
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(engine, adapter.getTable(), adapter.TableNamePrefix)
if err != nil {
return err
}
}
return nil return nil
} }
engine, err := xorm.NewEngine(a.driverName, a.dataSourceName) func adapterChangeTrigger(oldName string, newName string) error {
session := ormer.Engine.NewSession()
defer session.Close()
err := session.Begin()
if err != nil { if err != nil {
return err return err
} }
defer engine.Close()
_, err = engine.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8mb4 COLLATE utf8mb4_general_ci", a.dbName)) enforcer := new(Enforcer)
enforcer.Adapter = newName
_, err = session.Where("adapter=?", oldName).Update(enforcer)
if err != nil {
session.Rollback()
return err return err
} }
func (a *Adapter) open() { return session.Commit()
dataSourceName := a.dataSourceName + a.dbName
if a.driverName != "mysql" {
dataSourceName = a.dataSourceName
} }
engine, err := xorm.NewEngine(a.driverName, dataSourceName) func safeReturn(policy []string, i int) string {
if err != nil { if len(policy) > i {
panic(err) return policy[i]
}
a.Engine = engine
}
func (a *Adapter) close() {
_ = a.Engine.Close()
a.Engine = nil
}
func (a *Adapter) createTable() {
showSql := conf.GetConfigBool("showSql")
a.Engine.ShowSQL(showSql)
err := a.Engine.Sync2(new(Organization))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(User))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Group))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Role))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Permission))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Model))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(CasbinAdapter))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Enforcer))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Provider))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Application))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Resource))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Token))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(VerificationRecord))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Record))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Webhook))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Syncer))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Cert))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Chat))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Message))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Product))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Payment))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Ldap))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(PermissionRule))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(xormadapter.CasbinRule))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Session))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Subscription))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Plan))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Pricing))
if err != nil {
panic(err)
}
}
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
session := adapter.Engine.Prepare()
if offset != -1 && limit != -1 {
session.Limit(limit, offset)
}
if owner != "" {
session = session.And("owner=?", owner)
}
if field != "" && value != "" {
if util.FilterField(field) {
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
}
}
if sortField == "" || sortOrder == "" {
sortField = "created_time"
}
if sortOrder == "ascend" {
session = session.Asc(util.SnakeString(sortField))
} else { } else {
session = session.Desc(util.SnakeString(sortField)) return ""
}
return session
}
func GetSessionForUser(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
session := adapter.Engine.Prepare()
if offset != -1 && limit != -1 {
session.Limit(limit, offset)
}
if owner != "" {
if offset == -1 {
session = session.And("owner=?", owner)
} else {
session = session.And("a.owner=?", owner)
}
}
if field != "" && value != "" {
if util.FilterField(field) {
if offset != -1 {
field = fmt.Sprintf("a.%s", field)
}
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
}
}
if sortField == "" || sortOrder == "" {
sortField = "created_time"
}
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
tableName := tableNamePrefix + "user"
if offset == -1 {
if sortOrder == "ascend" {
session = session.Asc(util.SnakeString(sortField))
} else {
session = session.Desc(util.SnakeString(sortField))
}
} else {
if sortOrder == "ascend" {
session = session.Alias("a").
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
Select("b.*").
Asc("a." + util.SnakeString(sortField))
} else {
session = session.Alias("a").
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
Select("b.*").
Desc("a." + util.SnakeString(sortField))
} }
} }
return session func matrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
res := []*xormadapter.CasbinRule{}
for _, policy := range policies {
line := xormadapter.CasbinRule{
Ptype: Ptype,
V0: safeReturn(policy, 0),
V1: safeReturn(policy, 1),
V2: safeReturn(policy, 2),
V3: safeReturn(policy, 3),
V4: safeReturn(policy, 4),
V5: safeReturn(policy, 5),
}
res = append(res, &line)
}
return res
}
func GetPolicies(adapter *Adapter) ([]*xormadapter.CasbinRule, error) {
err := adapter.initAdapter()
if err != nil {
return nil, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return nil, err
}
policies := matrixToCasbinRules("p", casbinModel.GetPolicy("p", "p"))
policies = append(policies, matrixToCasbinRules("g", casbinModel.GetPolicy("g", "g"))...)
return policies, nil
}
func UpdatePolicy(oldPolicy, newPolicy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
affected := casbinModel.UpdatePolicy("p", "p", oldPolicy, newPolicy)
if err != nil {
return affected, err
}
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return affected, nil
}
func AddPolicy(policy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
casbinModel.AddPolicy("p", "p", policy)
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return true, nil
}
func RemovePolicy(policy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
affected := casbinModel.RemovePolicy("p", "p", policy)
if err != nil {
return affected, err
}
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return affected, nil
}
func (adapter *Adapter) builtInAdapter() bool {
if adapter.Owner != "built-in" {
return false
}
return adapter.Name == "user-adapter-built-in" || adapter.Name == "api-adapter-built-in"
}
func getModelDef() model.Model {
casbinModel := model.NewModel()
casbinModel.AddDef("p", "p", "_, _, _, _, _, _")
casbinModel.AddDef("g", "g", "_, _, _, _, _, _")
return casbinModel
} }

View File

@ -92,7 +92,7 @@ func GetOrganizationApplicationCount(owner, Organization, field, value string) (
func GetApplications(owner string) ([]*Application, error) { func GetApplications(owner string) ([]*Application, error) {
applications := []*Application{} applications := []*Application{}
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&applications, &Application{Owner: owner})
if err != nil { if err != nil {
return applications, err return applications, err
} }
@ -102,7 +102,7 @@ func GetApplications(owner string) ([]*Application, error) {
func GetOrganizationApplications(owner string, organization string) ([]*Application, error) { func GetOrganizationApplications(owner string, organization string) ([]*Application, error) {
applications := []*Application{} applications := []*Application{}
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Organization: organization}) err := ormer.Engine.Desc("created_time").Find(&applications, &Application{Organization: organization})
if err != nil { if err != nil {
return applications, err return applications, err
} }
@ -182,7 +182,7 @@ func getApplication(owner string, name string) (*Application, error) {
} }
application := Application{Owner: owner, Name: name} application := Application{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&application) existed, err := ormer.Engine.Get(&application)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -206,7 +206,7 @@ func getApplication(owner string, name string) (*Application, error) {
func GetApplicationByOrganizationName(organization string) (*Application, error) { func GetApplicationByOrganizationName(organization string) (*Application, error) {
application := Application{} application := Application{}
existed, err := adapter.Engine.Where("organization=?", organization).Get(&application) existed, err := ormer.Engine.Where("organization=?", organization).Get(&application)
if err != nil { if err != nil {
return nil, nil return nil, nil
} }
@ -253,7 +253,7 @@ func GetApplicationByUserId(userId string) (application *Application, err error)
func GetApplicationByClientId(clientId string) (*Application, error) { func GetApplicationByClientId(clientId string) (*Application, error) {
application := Application{} application := Application{}
existed, err := adapter.Engine.Where("client_id=?", clientId).Get(&application) existed, err := ormer.Engine.Where("client_id=?", clientId).Get(&application)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -281,12 +281,19 @@ func GetApplication(id string) (*Application, error) {
} }
func GetMaskedApplication(application *Application, userId string) *Application { func GetMaskedApplication(application *Application, userId string) *Application {
if application == nil {
return nil
}
if userId != "" {
if isUserIdGlobalAdmin(userId) { if isUserIdGlobalAdmin(userId) {
return application return application
} }
if application == nil { user, _ := GetUser(userId)
return nil if user != nil && user.IsApplicationAdmin(application) {
return application
}
} }
if application.ClientSecret != "" { if application.ClientSecret != "" {
@ -349,7 +356,7 @@ func UpdateApplication(id string, application *Application) (bool, error) {
providerItem.Provider = nil providerItem.Provider = nil
} }
session := adapter.Engine.ID(core.PK{owner, name}).AllCols() session := ormer.Engine.ID(core.PK{owner, name}).AllCols()
if application.ClientSecret == "***" { if application.ClientSecret == "***" {
session.Omit("client_secret") session.Omit("client_secret")
} }
@ -388,7 +395,7 @@ func AddApplication(application *Application) (bool, error) {
providerItem.Provider = nil providerItem.Provider = nil
} }
affected, err := adapter.Engine.Insert(application) affected, err := ormer.Engine.Insert(application)
if err != nil { if err != nil {
return false, nil return false, nil
} }
@ -401,7 +408,7 @@ func DeleteApplication(application *Application) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{}) affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -477,7 +484,7 @@ func ExtendManagedAccountsWithUser(user *User) (*User, error) {
} }
func applicationChangeTrigger(oldName string, newName string) error { func applicationChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -507,7 +514,7 @@ func applicationChangeTrigger(oldName string, newName string) error {
} }
var permissions []*Permission var permissions []*Permission
err = adapter.Engine.Find(&permissions) err = ormer.Engine.Find(&permissions)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,313 +0,0 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/core"
)
type CasbinAdapter 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"`
Type string `xorm:"varchar(100)" json:"type"`
Model string `xorm:"varchar(100)" json:"model"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
User string `xorm:"varchar(100)" json:"user"`
Password string `xorm:"varchar(100)" json:"password"`
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
Database string `xorm:"varchar(100)" json:"database"`
Table string `xorm:"varchar(100)" json:"table"`
IsEnabled bool `json:"isEnabled"`
Adapter *xormadapter.Adapter `xorm:"-" json:"-"`
}
func GetCasbinAdapterCount(owner, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&CasbinAdapter{})
}
func GetCasbinAdapters(owner string) ([]*CasbinAdapter, error) {
adapters := []*CasbinAdapter{}
err := adapter.Engine.Desc("created_time").Find(&adapters, &CasbinAdapter{Owner: owner})
if err != nil {
return adapters, err
}
return adapters, nil
}
func GetPaginationCasbinAdapters(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*CasbinAdapter, error) {
adapters := []*CasbinAdapter{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&adapters)
if err != nil {
return adapters, err
}
return adapters, nil
}
func getCasbinAdapter(owner, name string) (*CasbinAdapter, error) {
if owner == "" || name == "" {
return nil, nil
}
casbinAdapter := CasbinAdapter{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&casbinAdapter)
if err != nil {
return nil, err
}
if existed {
return &casbinAdapter, nil
} else {
return nil, nil
}
}
func GetCasbinAdapter(id string) (*CasbinAdapter, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getCasbinAdapter(owner, name)
}
func UpdateCasbinAdapter(id string, casbinAdapter *CasbinAdapter) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if casbinAdapter, err := getCasbinAdapter(owner, name); casbinAdapter == nil {
return false, err
}
if name != casbinAdapter.Name {
err := casbinAdapterChangeTrigger(name, casbinAdapter.Name)
if err != nil {
return false, err
}
}
session := adapter.Engine.ID(core.PK{owner, name}).AllCols()
if casbinAdapter.Password == "***" {
session.Omit("password")
}
affected, err := session.Update(casbinAdapter)
if err != nil {
return false, err
}
return affected != 0, nil
}
func AddCasbinAdapter(casbinAdapter *CasbinAdapter) (bool, error) {
affected, err := adapter.Engine.Insert(casbinAdapter)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteCasbinAdapter(casbinAdapter *CasbinAdapter) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{casbinAdapter.Owner, casbinAdapter.Name}).Delete(&CasbinAdapter{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (casbinAdapter *CasbinAdapter) GetId() string {
return fmt.Sprintf("%s/%s", casbinAdapter.Owner, casbinAdapter.Name)
}
func (casbinAdapter *CasbinAdapter) getTable() string {
if casbinAdapter.DatabaseType == "mssql" {
return fmt.Sprintf("[%s]", casbinAdapter.Table)
} else {
return casbinAdapter.Table
}
}
func initEnforcer(modelObj *Model, casbinAdapter *CasbinAdapter) (*casbin.Enforcer, error) {
// init Adapter
if casbinAdapter.Adapter == nil {
var dataSourceName string
if casbinAdapter.DatabaseType == "mssql" {
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
} else if casbinAdapter.DatabaseType == "postgres" {
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
} else {
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port)
}
if !isCloudIntranet {
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
}
var err error
casbinAdapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(casbinAdapter.DatabaseType, dataSourceName, casbinAdapter.Database).Engine, casbinAdapter.getTable(), "")
if err != nil {
return nil, err
}
}
// init Model
m, err := model.NewModelFromString(modelObj.ModelText)
if err != nil {
return nil, err
}
// init Enforcer
enforcer, err := casbin.NewEnforcer(m, casbinAdapter.Adapter)
if err != nil {
return nil, err
}
return enforcer, nil
}
func casbinAdapterChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession()
defer session.Close()
err := session.Begin()
if err != nil {
return err
}
enforcer := new(Enforcer)
enforcer.Adapter = newName
_, err = session.Where("adapter=?", oldName).Update(enforcer)
if err != nil {
session.Rollback()
return err
}
return session.Commit()
}
func safeReturn(policy []string, i int) string {
if len(policy) > i {
return policy[i]
} else {
return ""
}
}
func matrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
res := []*xormadapter.CasbinRule{}
for _, policy := range policies {
line := xormadapter.CasbinRule{
Ptype: Ptype,
V0: safeReturn(policy, 0),
V1: safeReturn(policy, 1),
V2: safeReturn(policy, 2),
V3: safeReturn(policy, 3),
V4: safeReturn(policy, 4),
V5: safeReturn(policy, 5),
}
res = append(res, &line)
}
return res
}
func SyncPolicies(casbinAdapter *CasbinAdapter) ([]*xormadapter.CasbinRule, error) {
modelObj, err := getModel(casbinAdapter.Owner, casbinAdapter.Model)
if err != nil {
return nil, err
}
if modelObj == nil {
return nil, fmt.Errorf("The model: %s does not exist", util.GetId(casbinAdapter.Owner, casbinAdapter.Model))
}
enforcer, err := initEnforcer(modelObj, casbinAdapter)
if err != nil {
return nil, err
}
policies := matrixToCasbinRules("p", enforcer.GetPolicy())
if strings.Contains(modelObj.ModelText, "[role_definition]") {
policies = append(policies, matrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
}
return policies, nil
}
func UpdatePolicy(oldPolicy, newPolicy []string, casbinAdapter *CasbinAdapter) (bool, error) {
modelObj, err := getModel(casbinAdapter.Owner, casbinAdapter.Model)
if err != nil {
return false, err
}
enforcer, err := initEnforcer(modelObj, casbinAdapter)
if err != nil {
return false, err
}
affected, err := enforcer.UpdatePolicy(oldPolicy, newPolicy)
if err != nil {
return affected, err
}
return affected, nil
}
func AddPolicy(policy []string, casbinAdapter *CasbinAdapter) (bool, error) {
modelObj, err := getModel(casbinAdapter.Owner, casbinAdapter.Model)
if err != nil {
return false, err
}
enforcer, err := initEnforcer(modelObj, casbinAdapter)
if err != nil {
return false, err
}
affected, err := enforcer.AddPolicy(policy)
if err != nil {
return affected, err
}
return affected, nil
}
func RemovePolicy(policy []string, casbinAdapter *CasbinAdapter) (bool, error) {
modelObj, err := getModel(casbinAdapter.Owner, casbinAdapter.Model)
if err != nil {
return false, err
}
enforcer, err := initEnforcer(modelObj, casbinAdapter)
if err != nil {
return false, err
}
affected, err := enforcer.RemovePolicy(policy)
if err != nil {
return affected, err
}
return affected, nil
}

View File

@ -65,7 +65,7 @@ func GetCertCount(owner, field, value string) (int64, error) {
func GetCerts(owner string) ([]*Cert, error) { func GetCerts(owner string) ([]*Cert, error) {
certs := []*Cert{} certs := []*Cert{}
err := adapter.Engine.Where("owner = ? or owner = ? ", "admin", owner).Desc("created_time").Find(&certs, &Cert{}) err := ormer.Engine.Where("owner = ? or owner = ? ", "admin", owner).Desc("created_time").Find(&certs, &Cert{})
if err != nil { if err != nil {
return certs, err return certs, err
} }
@ -91,7 +91,7 @@ func GetGlobalCertsCount(field, value string) (int64, error) {
func GetGlobleCerts() ([]*Cert, error) { func GetGlobleCerts() ([]*Cert, error) {
certs := []*Cert{} certs := []*Cert{}
err := adapter.Engine.Desc("created_time").Find(&certs) err := ormer.Engine.Desc("created_time").Find(&certs)
if err != nil { if err != nil {
return certs, err return certs, err
} }
@ -116,7 +116,7 @@ func getCert(owner string, name string) (*Cert, error) {
} }
cert := Cert{Owner: owner, Name: name} cert := Cert{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&cert) existed, err := ormer.Engine.Get(&cert)
if err != nil { if err != nil {
return &cert, err return &cert, err
} }
@ -134,7 +134,7 @@ func getCertByName(name string) (*Cert, error) {
} }
cert := Cert{Name: name} cert := Cert{Name: name}
existed, err := adapter.Engine.Get(&cert) existed, err := ormer.Engine.Get(&cert)
if err != nil { if err != nil {
return &cert, nil return &cert, nil
} }
@ -162,10 +162,10 @@ 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 := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(cert) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(cert)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -180,7 +180,7 @@ func AddCert(cert *Cert) (bool, error) {
cert.PrivateKey = privateKey cert.PrivateKey = privateKey
} }
affected, err := adapter.Engine.Insert(cert) affected, err := ormer.Engine.Insert(cert)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -189,7 +189,7 @@ func AddCert(cert *Cert) (bool, error) {
} }
func DeleteCert(cert *Cert) (bool, error) { func DeleteCert(cert *Cert) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{cert.Owner, cert.Name}).Delete(&Cert{}) affected, err := ormer.Engine.ID(core.PK{cert.Owner, cert.Name}).Delete(&Cert{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -214,7 +214,7 @@ func GetDefaultCert() (*Cert, error) {
} }
func certChangeTrigger(oldName string, newName string) error { func certChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()

View File

@ -1,166 +0,0 @@
// 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 object
import (
"fmt"
"github.com/casdoor/casdoor/util"
"github.com/xorm-io/core"
)
type Chat 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"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
Organization string `xorm:"varchar(100)" json:"organization"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Type string `xorm:"varchar(100)" json:"type"`
Category string `xorm:"varchar(100)" json:"category"`
User1 string `xorm:"varchar(100)" json:"user1"`
User2 string `xorm:"varchar(100)" json:"user2"`
Users []string `xorm:"varchar(100)" json:"users"`
MessageCount int `json:"messageCount"`
}
func GetMaskedChat(chat *Chat, err ...error) (*Chat, error) {
if len(err) > 0 && err[0] != nil {
return nil, err[0]
}
if chat == nil {
return nil, nil
}
return chat, nil
}
func GetMaskedChats(chats []*Chat, errs ...error) ([]*Chat, error) {
if len(errs) > 0 && errs[0] != nil {
return nil, errs[0]
}
var err error
for _, chat := range chats {
chat, err = GetMaskedChat(chat)
if err != nil {
return nil, err
}
}
return chats, nil
}
func GetChatCount(owner, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&Chat{})
}
func GetChats(owner string) ([]*Chat, error) {
chats := []*Chat{}
err := adapter.Engine.Desc("created_time").Find(&chats, &Chat{Owner: owner})
if err != nil {
return chats, err
}
return chats, nil
}
func GetPaginationChats(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Chat, error) {
chats := []*Chat{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&chats)
if err != nil {
return chats, err
}
return chats, nil
}
func getChat(owner string, name string) (*Chat, error) {
if owner == "" || name == "" {
return nil, nil
}
chat := Chat{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&chat)
if err != nil {
return &chat, err
}
if existed {
return &chat, nil
} else {
return nil, nil
}
}
func GetChat(id string) (*Chat, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getChat(owner, name)
}
func UpdateChat(id string, chat *Chat) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if c, err := getChat(owner, name); err != nil {
return false, err
} else if c == nil {
return false, nil
}
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(chat)
if err != nil {
return false, nil
}
return affected != 0, nil
}
func AddChat(chat *Chat) (bool, error) {
if chat.Type == "AI" && chat.User2 == "" {
provider, err := getDefaultAiProvider()
if err != nil {
return false, err
}
if provider != nil {
chat.User2 = provider.Name
}
}
affected, err := adapter.Engine.Insert(chat)
if err != nil {
return false, nil
}
return affected != 0, nil
}
func DeleteChat(chat *Chat) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{chat.Owner, chat.Name}).Delete(&Chat{})
if err != nil {
return false, err
}
if affected != 0 {
return DeleteChatMessages(chat.Name)
}
return affected != 0, nil
}
func (p *Chat) GetId() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
}

View File

@ -15,6 +15,8 @@
package object package object
import ( import (
"fmt"
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/xorm-io/core" "github.com/xorm-io/core"
@ -42,7 +44,7 @@ func GetEnforcerCount(owner, field, value string) (int64, error) {
func GetEnforcers(owner string) ([]*Enforcer, error) { func GetEnforcers(owner string) ([]*Enforcer, error) {
enforcers := []*Enforcer{} enforcers := []*Enforcer{}
err := adapter.Engine.Desc("created_time").Find(&enforcers, &Enforcer{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&enforcers, &Enforcer{Owner: owner})
if err != nil { if err != nil {
return enforcers, err return enforcers, err
} }
@ -67,7 +69,7 @@ func getEnforcer(owner string, name string) (*Enforcer, error) {
} }
enforcer := Enforcer{Owner: owner, Name: name} enforcer := Enforcer{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&enforcer) existed, err := ormer.Engine.Get(&enforcer)
if err != nil { if err != nil {
return &enforcer, err return &enforcer, err
} }
@ -92,7 +94,7 @@ func UpdateEnforcer(id string, enforcer *Enforcer) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(enforcer) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(enforcer)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -101,7 +103,7 @@ func UpdateEnforcer(id string, enforcer *Enforcer) (bool, error) {
} }
func AddEnforcer(enforcer *Enforcer) (bool, error) { func AddEnforcer(enforcer *Enforcer) (bool, error) {
affected, err := adapter.Engine.Insert(enforcer) affected, err := ormer.Engine.Insert(enforcer)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -110,10 +112,73 @@ func AddEnforcer(enforcer *Enforcer) (bool, error) {
} }
func DeleteEnforcer(enforcer *Enforcer) (bool, error) { func DeleteEnforcer(enforcer *Enforcer) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{enforcer.Owner, enforcer.Name}).Delete(&Enforcer{}) affected, err := ormer.Engine.ID(core.PK{enforcer.Owner, enforcer.Name}).Delete(&Enforcer{})
if err != nil { if err != nil {
return false, err return false, err
} }
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 {
if enforcer.Enforcer != nil {
return nil
}
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
}
func GetInitializedEnforcer(enforcerId string) (*Enforcer, error) {
enforcer, err := GetEnforcer(enforcerId)
if err != nil {
return nil, err
} else if enforcer == nil {
return nil, fmt.Errorf("the enforcer: %s is not found", enforcerId)
}
err = enforcer.InitEnforcer()
if err != nil {
return nil, err
}
return enforcer, nil
}

View File

@ -58,7 +58,7 @@ func GetGroupCount(owner, field, value string) (int64, error) {
func GetGroups(owner string) ([]*Group, error) { func GetGroups(owner string) ([]*Group, error) {
groups := []*Group{} groups := []*Group{}
err := adapter.Engine.Desc("created_time").Find(&groups, &Group{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&groups, &Group{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,7 +83,7 @@ func getGroup(owner string, name string) (*Group, error) {
} }
group := Group{Owner: owner, Name: name} group := Group{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&group) existed, err := ormer.Engine.Get(&group)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -119,7 +119,7 @@ func UpdateGroup(id string, group *Group) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(group) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(group)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -133,7 +133,7 @@ func AddGroup(group *Group) (bool, error) {
return false, err return false, err
} }
affected, err := adapter.Engine.Insert(group) affected, err := ormer.Engine.Insert(group)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -145,7 +145,7 @@ func AddGroups(groups []*Group) (bool, error) {
if len(groups) == 0 { if len(groups) == 0 {
return false, nil return false, nil
} }
affected, err := adapter.Engine.Insert(groups) affected, err := ormer.Engine.Insert(groups)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -153,24 +153,24 @@ func AddGroups(groups []*Group) (bool, error) {
} }
func DeleteGroup(group *Group) (bool, error) { func DeleteGroup(group *Group) (bool, error) {
_, err := adapter.Engine.Get(group) _, err := ormer.Engine.Get(group)
if err != nil { if err != nil {
return false, err return false, err
} }
if count, err := adapter.Engine.Where("parent_id = ?", group.Name).Count(&Group{}); err != nil { if count, err := ormer.Engine.Where("parent_id = ?", group.Name).Count(&Group{}); err != nil {
return false, err return false, err
} else if count > 0 { } else if count > 0 {
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")
} }
affected, err := adapter.Engine.ID(core.PK{group.Owner, group.Name}).Delete(&Group{}) affected, err := ormer.Engine.ID(core.PK{group.Owner, group.Name}).Delete(&Group{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -179,7 +179,7 @@ func DeleteGroup(group *Group) (bool, error) {
} }
func checkGroupName(name string) error { func checkGroupName(name string) error {
exist, err := adapter.Engine.Exist(&Organization{Owner: "admin", Name: name}) exist, err := ormer.Engine.Exist(&Organization{Owner: "admin", Name: name})
if err != nil { if err != nil {
return err return err
} }
@ -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 adapter.Engine.Where(builder.Like{"`groups`", groupName}). return int64(len(names)), nil
Count(&User{})
} else { } else {
return adapter.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{}
session := adapter.Engine.Table("user"). owner, _ := util.GetOwnerAndNameFromId(groupId)
Where(builder.Like{"`groups`", groupName + "\""}) names, err := userEnforcer.GetUserNamesByGroupName(groupId)
if err != nil {
return nil, err
}
session := ormer.Engine.Table("user").
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,20 +267,20 @@ 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 := adapter.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
} }
func GroupChangeTrigger(oldName, newName string) error { func GroupChangeTrigger(oldName, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
if err != nil { if err != nil {

View File

@ -27,7 +27,6 @@ import (
func InitDb() { func InitDb() {
existed := initBuiltInOrganization() existed := initBuiltInOrganization()
if !existed { if !existed {
initBuiltInModel()
initBuiltInPermission() initBuiltInPermission()
initBuiltInProvider() initBuiltInProvider()
initBuiltInUser() initBuiltInUser()
@ -36,6 +35,15 @@ func InitDb() {
initBuiltInLdap() initBuiltInLdap()
} }
existed = initBuiltInApiModel()
if !existed {
initBuiltInApiAdapter()
initBuiltInApiEnforcer()
initBuiltInUserModel()
initBuiltInUserAdapter()
initBuiltInUserEnforcer()
}
initWebAuthn() initWebAuthn()
} }
@ -295,8 +303,8 @@ func initWebAuthn() {
gob.Register(webauthn.SessionData{}) gob.Register(webauthn.SessionData{})
} }
func initBuiltInModel() { func initBuiltInUserModel() {
model, err := GetModel("built-in/model-built-in") model, err := GetModel("built-in/user-model-built-in")
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -307,7 +315,7 @@ func initBuiltInModel() {
model = &Model{ model = &Model{
Owner: "built-in", Owner: "built-in",
Name: "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,
@ -317,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 {
@ -329,6 +340,52 @@ m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`,
} }
} }
func initBuiltInApiModel() bool {
model, err := GetModel("built-in/api-model-built-in")
if err != nil {
panic(err)
}
if model != nil {
return true
}
modelText := `[request_definition]
r = subOwner, subName, method, urlPath, objOwner, objName
[policy_definition]
p = subOwner, subName, method, urlPath, objOwner, objName
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
(r.subName == p.subName || p.subName == "*" || r.subName != "anonymous" && p.subName == "!anonymous") && \
(r.method == p.method || p.method == "*") && \
(r.urlPath == p.urlPath || p.urlPath == "*") && \
(r.objOwner == p.objOwner || p.objOwner == "*") && \
(r.objName == p.objName || p.objName == "*") || \
(r.subOwner == r.objOwner && r.subName == r.objName)`
model = &Model{
Owner: "built-in",
Name: "api-model-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "API Model",
IsEnabled: true,
ModelText: modelText,
}
_, err = AddModel(model)
if err != nil {
panic(err)
}
return false
}
func initBuiltInPermission() { func initBuiltInPermission() {
permission, err := GetPermission("built-in/permission-built-in") permission, err := GetPermission("built-in/permission-built-in")
if err != nil { if err != nil {
@ -358,3 +415,109 @@ func initBuiltInPermission() {
panic(err) panic(err)
} }
} }
func initBuiltInUserAdapter() {
adapter, err := GetAdapter("built-in/user-adapter-built-in")
if err != nil {
panic(err)
}
if adapter != nil {
return
}
adapter = &Adapter{
Owner: "built-in",
Name: "user-adapter-built-in",
CreatedTime: util.GetCurrentTime(),
Type: "Database",
DatabaseType: conf.GetConfigString("driverName"),
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
Database: conf.GetConfigString("dbName"),
Table: "casbin_user_rule",
IsEnabled: true,
}
_, err = AddAdapter(adapter)
if err != nil {
panic(err)
}
}
func initBuiltInApiAdapter() {
adapter, err := GetAdapter("built-in/api-adapter-built-in")
if err != nil {
panic(err)
}
if adapter != nil {
return
}
adapter = &Adapter{
Owner: "built-in",
Name: "api-adapter-built-in",
CreatedTime: util.GetCurrentTime(),
Type: "Database",
DatabaseType: conf.GetConfigString("driverName"),
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
Database: conf.GetConfigString("dbName"),
Table: "casbin_api_rule",
IsEnabled: true,
}
_, err = AddAdapter(adapter)
if err != nil {
panic(err)
}
}
func initBuiltInUserEnforcer() {
enforcer, err := GetEnforcer("built-in/user-enforcer-built-in")
if err != nil {
panic(err)
}
if enforcer != nil {
return
}
enforcer = &Enforcer{
Owner: "built-in",
Name: "user-enforcer-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "User Enforcer",
Model: "built-in/user-model-built-in",
Adapter: "built-in/user-adapter-built-in",
IsEnabled: true,
}
_, err = AddEnforcer(enforcer)
if err != nil {
panic(err)
}
}
func initBuiltInApiEnforcer() {
enforcer, err := GetEnforcer("built-in/api-enforcer-built-in")
if err != nil {
panic(err)
}
if enforcer != nil {
return
}
enforcer = &Enforcer{
Owner: "built-in",
Name: "api-enforcer-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "API Enforcer",
Model: "built-in/api-model-built-in",
Adapter: "built-in/api-adapter-built-in",
IsEnabled: true,
}
_, err = AddEnforcer(enforcer)
if err != nil {
panic(err)
}
}

View File

@ -46,7 +46,7 @@ func AddLdap(ldap *Ldap) (bool, error) {
ldap.CreatedTime = util.GetCurrentTime() ldap.CreatedTime = util.GetCurrentTime()
} }
affected, err := adapter.Engine.Insert(ldap) affected, err := ormer.Engine.Insert(ldap)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -56,7 +56,7 @@ func AddLdap(ldap *Ldap) (bool, error) {
func CheckLdapExist(ldap *Ldap) (bool, error) { func CheckLdapExist(ldap *Ldap) (bool, error) {
var result []*Ldap var result []*Ldap
err := adapter.Engine.Find(&result, &Ldap{ err := ormer.Engine.Find(&result, &Ldap{
Owner: ldap.Owner, Owner: ldap.Owner,
Host: ldap.Host, Host: ldap.Host,
Port: ldap.Port, Port: ldap.Port,
@ -77,7 +77,7 @@ func CheckLdapExist(ldap *Ldap) (bool, error) {
func GetLdaps(owner string) ([]*Ldap, error) { func GetLdaps(owner string) ([]*Ldap, error) {
var ldaps []*Ldap var ldaps []*Ldap
err := adapter.Engine.Desc("created_time").Find(&ldaps, &Ldap{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&ldaps, &Ldap{Owner: owner})
if err != nil { if err != nil {
return ldaps, err return ldaps, err
} }
@ -91,7 +91,7 @@ func GetLdap(id string) (*Ldap, error) {
} }
ldap := Ldap{Id: id} ldap := Ldap{Id: id}
existed, err := adapter.Engine.Get(&ldap) existed, err := ormer.Engine.Get(&ldap)
if err != nil { if err != nil {
return &ldap, nil return &ldap, nil
} }
@ -135,13 +135,19 @@ func GetMaskedLdaps(ldaps []*Ldap, errs ...error) ([]*Ldap, error) {
} }
func UpdateLdap(ldap *Ldap) (bool, error) { func UpdateLdap(ldap *Ldap) (bool, error) {
if l, err := GetLdap(ldap.Id); err != nil { var l *Ldap
var err error
if l, err = GetLdap(ldap.Id); err != nil {
return false, nil return false, nil
} else if l == nil { } else if l == nil {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(ldap.Id).Cols("owner", "server_name", "host", if ldap.Password == "***" {
ldap.Password = l.Password
}
affected, err := ormer.Engine.ID(ldap.Id).Cols("owner", "server_name", "host",
"port", "enable_ssl", "username", "password", "base_dn", "filter", "filter_fields", "auto_sync").Update(ldap) "port", "enable_ssl", "username", "password", "base_dn", "filter", "filter_fields", "auto_sync").Update(ldap)
if err != nil { if err != nil {
return false, nil return false, nil
@ -151,7 +157,7 @@ func UpdateLdap(ldap *Ldap) (bool, error) {
} }
func DeleteLdap(ldap *Ldap) (bool, error) { func DeleteLdap(ldap *Ldap) (bool, error) {
affected, err := adapter.Engine.ID(ldap.Id).Delete(&Ldap{}) affected, err := ormer.Engine.ID(ldap.Id).Delete(&Ldap{})
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -118,7 +118,7 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) e
// start all autosync goroutine for existing ldap servers in each organizations // start all autosync goroutine for existing ldap servers in each organizations
func (l *LdapAutoSynchronizer) LdapAutoSynchronizerStartUpAll() error { func (l *LdapAutoSynchronizer) LdapAutoSynchronizerStartUpAll() error {
organizations := []*Organization{} organizations := []*Organization{}
err := adapter.Engine.Desc("created_time").Find(&organizations) err := ormer.Engine.Desc("created_time").Find(&organizations)
if err != nil { if err != nil {
logs.Info("failed to Star up LdapAutoSynchronizer; ") logs.Info("failed to Star up LdapAutoSynchronizer; ")
} }
@ -141,7 +141,7 @@ func (l *LdapAutoSynchronizer) LdapAutoSynchronizerStartUpAll() error {
} }
func UpdateLdapSyncTime(ldapId string) error { func UpdateLdapSyncTime(ldapId string) error {
_, err := adapter.Engine.ID(ldapId).Update(&Ldap{LastSync: util.GetCurrentTime()}) _, err := ormer.Engine.ID(ldapId).Update(&Ldap{LastSync: util.GetCurrentTime()})
if err != nil { if err != nil {
return err return err
} }

View File

@ -41,19 +41,20 @@ 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"`
EmailAddress string EmailAddress string
TelephoneNumber string TelephoneNumber string
Mobile string Mobile string `json:"mobile"`
MobileTelephoneNumber string MobileTelephoneNumber string
RegisteredAddress string RegisteredAddress string
PostalAddress string PostalAddress string
GroupId string `json:"groupId"` GroupId string `json:"groupId"`
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 +169,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 +189,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)
@ -312,7 +317,7 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
DisplayName: syncUser.buildLdapDisplayName(), DisplayName: syncUser.buildLdapDisplayName(),
Avatar: organization.DefaultAvatar, Avatar: organization.DefaultAvatar,
Email: syncUser.Email, Email: syncUser.Email,
Phone: syncUser.Phone, Phone: syncUser.Mobile,
Address: []string{syncUser.Address}, Address: []string{syncUser.Address},
Affiliation: affiliation, Affiliation: affiliation,
Tag: tag, Tag: tag,
@ -338,7 +343,7 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
func GetExistUuids(owner string, uuids []string) ([]string, error) { func GetExistUuids(owner string, uuids []string) ([]string, error) {
var existUuids []string var existUuids []string
err := adapter.Engine.Table("user").Where("owner = ?", owner).Cols("ldap"). err := ormer.Engine.Table("user").Where("owner = ?", owner).Cols("ldap").
In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids) In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids)
if err != nil { if err != nil {
return existUuids, err return existUuids, err
@ -350,7 +355,7 @@ func GetExistUuids(owner string, uuids []string) ([]string, error) {
func (ldapUser *LdapUser) buildLdapUserName() (string, error) { func (ldapUser *LdapUser) buildLdapUserName() (string, error) {
user := User{} user := User{}
uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber) uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber)
has, err := adapter.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user) has, err := ormer.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -1,143 +0,0 @@
// 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 object
import (
"fmt"
"github.com/casdoor/casdoor/util"
"github.com/xorm-io/core"
)
type Message 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"`
Organization string `xorm:"varchar(100)" json:"organization"`
Chat string `xorm:"varchar(100) index" json:"chat"`
ReplyTo string `xorm:"varchar(100) index" json:"replyTo"`
Author string `xorm:"varchar(100)" json:"author"`
Text string `xorm:"mediumtext" json:"text"`
}
func GetMaskedMessage(message *Message) *Message {
if message == nil {
return nil
}
return message
}
func GetMaskedMessages(messages []*Message) []*Message {
for _, message := range messages {
message = GetMaskedMessage(message)
}
return messages
}
func GetMessageCount(owner, organization, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&Message{Organization: organization})
}
func GetMessages(owner string) ([]*Message, error) {
messages := []*Message{}
err := adapter.Engine.Desc("created_time").Find(&messages, &Message{Owner: owner})
return messages, err
}
func GetChatMessages(chat string) ([]*Message, error) {
messages := []*Message{}
err := adapter.Engine.Asc("created_time").Find(&messages, &Message{Chat: chat})
return messages, err
}
func GetPaginationMessages(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Message, error) {
messages := []*Message{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&messages, &Message{Organization: organization})
return messages, err
}
func getMessage(owner string, name string) (*Message, error) {
if owner == "" || name == "" {
return nil, nil
}
message := Message{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&message)
if err != nil {
return nil, err
}
if existed {
return &message, nil
} else {
return nil, nil
}
}
func GetMessage(id string) (*Message, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getMessage(owner, name)
}
func UpdateMessage(id string, message *Message) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if m, err := getMessage(owner, name); err != nil {
return false, err
} else if m == nil {
return false, nil
}
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(message)
if err != nil {
return false, err
}
return affected != 0, nil
}
func AddMessage(message *Message) (bool, error) {
affected, err := adapter.Engine.Insert(message)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteMessage(message *Message) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{message.Owner, message.Name}).Delete(&Message{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteChatMessages(chat string) (bool, error) {
affected, err := adapter.Engine.Delete(&Message{Chat: chat})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (p *Message) GetId() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
}

View File

@ -43,7 +43,7 @@ func DoMigration() {
IDColumnName: "id", IDColumnName: "id",
} }
m := migrate.New(adapter.Engine, options, migrations) m := migrate.New(ormer.Engine, options, migrations)
err := m.Migrate() err := m.Migrate()
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -24,9 +24,9 @@ import (
type Migrator_1_101_0_PR_1083 struct{} type Migrator_1_101_0_PR_1083 struct{}
func (*Migrator_1_101_0_PR_1083) IsMigrationNeeded() bool { func (*Migrator_1_101_0_PR_1083) IsMigrationNeeded() bool {
exist1, _ := adapter.Engine.IsTableExist("model") exist1, _ := ormer.Engine.IsTableExist("model")
exist2, _ := adapter.Engine.IsTableExist("permission") exist2, _ := ormer.Engine.IsTableExist("permission")
exist3, _ := adapter.Engine.IsTableExist("permission_rule") exist3, _ := ormer.Engine.IsTableExist("permission_rule")
if exist1 && exist2 && exist3 { if exist1 && exist2 && exist3 {
return true return true

View File

@ -23,7 +23,7 @@ import (
type Migrator_1_235_0_PR_1530 struct{} type Migrator_1_235_0_PR_1530 struct{}
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool { func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("casbin_rule") exist, _ := ormer.Engine.IsTableExist("casbin_rule")
return exist return exist
} }

View File

@ -24,8 +24,8 @@ import (
type Migrator_1_240_0_PR_1539 struct{} type Migrator_1_240_0_PR_1539 struct{}
func (*Migrator_1_240_0_PR_1539) IsMigrationNeeded() bool { func (*Migrator_1_240_0_PR_1539) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("session") exist, _ := ormer.Engine.IsTableExist("session")
err := adapter.Engine.Table("session").Find(&[]*Session{}) err := ormer.Engine.Table("session").Find(&[]*Session{})
if exist && err != nil { if exist && err != nil {
return true return true

View File

@ -22,7 +22,7 @@ import (
type Migrator_1_314_0_PR_1841 struct{} type Migrator_1_314_0_PR_1841 struct{}
func (*Migrator_1_314_0_PR_1841) IsMigrationNeeded() bool { func (*Migrator_1_314_0_PR_1841) IsMigrationNeeded() bool {
count, err := adapter.Engine.Where("password_type=?", "").Count(&User{}) count, err := ormer.Engine.Where("password_type=?", "").Count(&User{})
if err != nil { if err != nil {
// table doesn't exist // table doesn't exist
return false return false

View File

@ -31,6 +31,8 @@ type Model struct {
ModelText string `xorm:"mediumtext" json:"modelText"` ModelText string `xorm:"mediumtext" json:"modelText"`
IsEnabled bool `json:"isEnabled"` IsEnabled bool `json:"isEnabled"`
model.Model `xorm:"-" json:"-"`
} }
func GetModelCount(owner, field, value string) (int64, error) { func GetModelCount(owner, field, value string) (int64, error) {
@ -40,7 +42,7 @@ func GetModelCount(owner, field, value string) (int64, error) {
func GetModels(owner string) ([]*Model, error) { func GetModels(owner string) ([]*Model, error) {
models := []*Model{} models := []*Model{}
err := adapter.Engine.Desc("created_time").Find(&models, &Model{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&models, &Model{Owner: owner})
if err != nil { if err != nil {
return models, err return models, err
} }
@ -65,7 +67,7 @@ func getModel(owner string, name string) (*Model, error) {
} }
m := Model{Owner: owner, Name: name} m := Model{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&m) existed, err := ormer.Engine.Get(&m)
if err != nil { if err != nil {
return &m, err return &m, err
} }
@ -111,7 +113,7 @@ func UpdateModel(id string, modelObj *Model) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(modelObj) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(modelObj)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -120,7 +122,7 @@ func UpdateModel(id string, modelObj *Model) (bool, error) {
} }
func AddModel(model *Model) (bool, error) { func AddModel(model *Model) (bool, error) {
affected, err := adapter.Engine.Insert(model) affected, err := ormer.Engine.Insert(model)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -129,7 +131,7 @@ func AddModel(model *Model) (bool, error) {
} }
func DeleteModel(model *Model) (bool, error) { func DeleteModel(model *Model) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{model.Owner, model.Name}).Delete(&Model{}) affected, err := ormer.Engine.ID(core.PK{model.Owner, model.Name}).Delete(&Model{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -137,12 +139,12 @@ func DeleteModel(model *Model) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func (model *Model) GetId() string { func (m *Model) GetId() string {
return fmt.Sprintf("%s/%s", model.Owner, model.Name) return fmt.Sprintf("%s/%s", m.Owner, m.Name)
} }
func modelChangeTrigger(oldName string, newName string) error { func modelChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -175,3 +177,15 @@ func HasRoleDefinition(m model.Model) bool {
} }
return m["g"] != nil return m["g"] != nil
} }
func (m *Model) initModel() error {
if m.Model == nil {
casbinModel, err := model.NewModelFromString(m.ModelText)
if err != nil {
return err
}
m.Model = casbinModel
}
return nil
}

View File

@ -80,12 +80,12 @@ func GetOrganizationCount(owner, field, value string) (int64, error) {
func GetOrganizations(owner string, name ...string) ([]*Organization, error) { func GetOrganizations(owner string, name ...string) ([]*Organization, error) {
organizations := []*Organization{} organizations := []*Organization{}
if name != nil && len(name) > 0 { if name != nil && len(name) > 0 {
err := adapter.Engine.Desc("created_time").Where(builder.In("name", name)).Find(&organizations) err := ormer.Engine.Desc("created_time").Where(builder.In("name", name)).Find(&organizations)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else { } else {
err := adapter.Engine.Desc("created_time").Find(&organizations, &Organization{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&organizations, &Organization{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -96,7 +96,7 @@ func GetOrganizations(owner string, name ...string) ([]*Organization, error) {
func GetOrganizationsByFields(owner string, fields ...string) ([]*Organization, error) { func GetOrganizationsByFields(owner string, fields ...string) ([]*Organization, error) {
organizations := []*Organization{} organizations := []*Organization{}
err := adapter.Engine.Desc("created_time").Cols(fields...).Find(&organizations, &Organization{Owner: owner}) err := ormer.Engine.Desc("created_time").Cols(fields...).Find(&organizations, &Organization{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -126,7 +126,7 @@ func getOrganization(owner string, name string) (*Organization, error) {
} }
organization := Organization{Owner: owner, Name: name} organization := Organization{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&organization) existed, err := ormer.Engine.Get(&organization)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -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
} }
} }
@ -201,7 +201,7 @@ func UpdateOrganization(id string, organization *Organization) (bool, error) {
} }
} }
session := adapter.Engine.ID(core.PK{owner, name}).AllCols() session := ormer.Engine.ID(core.PK{owner, name}).AllCols()
if organization.MasterPassword == "***" { if organization.MasterPassword == "***" {
session.Omit("master_password") session.Omit("master_password")
} }
@ -214,7 +214,7 @@ func UpdateOrganization(id string, organization *Organization) (bool, error) {
} }
func AddOrganization(organization *Organization) (bool, error) { func AddOrganization(organization *Organization) (bool, error) {
affected, err := adapter.Engine.Insert(organization) affected, err := ormer.Engine.Insert(organization)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -227,7 +227,7 @@ func DeleteOrganization(organization *Organization) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{organization.Owner, organization.Name}).Delete(&Organization{}) affected, err := ormer.Engine.ID(core.PK{organization.Owner, organization.Name}).Delete(&Organization{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -299,7 +299,7 @@ func GetDefaultApplication(id string) (*Application, error) {
} }
applications := []*Application{} applications := []*Application{}
err = adapter.Engine.Asc("created_time").Find(&applications, &Application{Organization: organization.Name}) err = ormer.Engine.Asc("created_time").Find(&applications, &Application{Organization: organization.Name})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -330,7 +330,7 @@ func GetDefaultApplication(id string) (*Application, error) {
} }
func organizationChangeTrigger(oldName string, newName string) error { func organizationChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -360,7 +360,7 @@ func organizationChangeTrigger(oldName string, newName string) error {
} }
role := new(Role) role := new(Role)
_, err = adapter.Engine.Where("owner=?", oldName).Get(role) _, err = ormer.Engine.Where("owner=?", oldName).Get(role)
if err != nil { if err != nil {
return err return err
} }
@ -385,7 +385,7 @@ func organizationChangeTrigger(oldName string, newName string) error {
} }
permission := new(Permission) permission := new(Permission)
_, err = adapter.Engine.Where("owner=?", oldName).Get(permission) _, err = ormer.Engine.Where("owner=?", oldName).Get(permission)
if err != nil { if err != nil {
return err return err
} }
@ -409,9 +409,9 @@ func organizationChangeTrigger(oldName string, newName string) error {
return err return err
} }
casbinAdapter := new(CasbinAdapter) adapter := new(Adapter)
casbinAdapter.Owner = newName adapter.Owner = newName
_, err = session.Where("owner=?", oldName).Update(casbinAdapter) _, err = session.Where("owner=?", oldName).Update(adapter)
if err != nil { if err != nil {
return err return err
} }
@ -431,8 +431,8 @@ func organizationChangeTrigger(oldName string, newName string) error {
} }
payment := new(Payment) payment := new(Payment)
payment.Organization = 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
} }

369
object/ormer.go Normal file
View File

@ -0,0 +1,369 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"database/sql"
"fmt"
"runtime"
"strings"
"github.com/beego/beego"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
"github.com/xorm-io/core"
"github.com/xorm-io/xorm"
_ "modernc.org/sqlite" // db = sqlite
)
var ormer *Ormer
func InitConfig() {
err := beego.LoadAppConfig("ini", "../conf/app.conf")
if err != nil {
panic(err)
}
beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true)
CreateTables(true)
DoMigration()
}
func InitAdapter(createDatabase bool) {
if createDatabase {
err := createDatabaseForPostgres(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
if err != nil {
panic(err)
}
}
ormer = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
ormer.Engine.SetTableMapper(tbMapper)
}
func CreateTables(createDatabase bool) {
if createDatabase {
err := ormer.CreateDatabase()
if err != nil {
panic(err)
}
}
ormer.createTable()
}
// Ormer represents the MySQL adapter for policy storage.
type Ormer struct {
driverName string
dataSourceName string
dbName string
Engine *xorm.Engine
}
// finalizer is the destructor for Ormer.
func finalizer(a *Ormer) {
err := a.Engine.Close()
if err != nil {
panic(err)
}
}
// NewAdapter is the constructor for Ormer.
func NewAdapter(driverName string, dataSourceName string, dbName string) *Ormer {
a := &Ormer{}
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 createDatabaseForPostgres(driverName string, dataSourceName string, dbName string) error {
if driverName == "postgres" {
db, err := sql.Open(driverName, dataSourceName)
if err != nil {
return err
}
defer db.Close()
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s;", dbName))
if err != nil {
if !strings.Contains(err.Error(), "already exists") {
return err
}
}
return nil
} else {
return nil
}
}
func (a *Ormer) CreateDatabase() error {
if a.driverName == "postgres" {
return nil
}
engine, err := xorm.NewEngine(a.driverName, a.dataSourceName)
if err != nil {
return err
}
defer engine.Close()
_, err = engine.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8mb4 COLLATE utf8mb4_general_ci", a.dbName))
return err
}
func (a *Ormer) open() {
dataSourceName := a.dataSourceName + a.dbName
if a.driverName != "mysql" {
dataSourceName = a.dataSourceName
}
engine, err := xorm.NewEngine(a.driverName, dataSourceName)
if err != nil {
panic(err)
}
a.Engine = engine
}
func (a *Ormer) close() {
_ = a.Engine.Close()
a.Engine = nil
}
func (a *Ormer) createTable() {
showSql := conf.GetConfigBool("showSql")
a.Engine.ShowSQL(showSql)
err := a.Engine.Sync2(new(Organization))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(User))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Group))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Role))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Permission))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Model))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Adapter))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Enforcer))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Provider))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Application))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Resource))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Token))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(VerificationRecord))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Record))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Webhook))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Syncer))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Cert))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Product))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Payment))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Ldap))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(PermissionRule))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(xormadapter.CasbinRule))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Session))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Subscription))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Plan))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Pricing))
if err != nil {
panic(err)
}
}
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
session := ormer.Engine.Prepare()
if offset != -1 && limit != -1 {
session.Limit(limit, offset)
}
if owner != "" {
session = session.And("owner=?", owner)
}
if field != "" && value != "" {
if util.FilterField(field) {
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
}
}
if sortField == "" || sortOrder == "" {
sortField = "created_time"
}
if sortOrder == "ascend" {
session = session.Asc(util.SnakeString(sortField))
} else {
session = session.Desc(util.SnakeString(sortField))
}
return session
}
func GetSessionForUser(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
session := ormer.Engine.Prepare()
if offset != -1 && limit != -1 {
session.Limit(limit, offset)
}
if owner != "" {
if offset == -1 {
session = session.And("owner=?", owner)
} else {
session = session.And("a.owner=?", owner)
}
}
if field != "" && value != "" {
if util.FilterField(field) {
if offset != -1 {
field = fmt.Sprintf("a.%s", field)
}
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
}
}
if sortField == "" || sortOrder == "" {
sortField = "created_time"
}
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
tableName := tableNamePrefix + "user"
if offset == -1 {
if sortOrder == "ascend" {
session = session.Asc(util.SnakeString(sortField))
} else {
session = session.Desc(util.SnakeString(sortField))
}
} else {
if sortOrder == "ascend" {
session = session.Alias("a").
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
Select("b.*").
Asc("a." + util.SnakeString(sortField))
} else {
session = session.Alias("a").
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
Select("b.*").
Desc("a." + util.SnakeString(sortField))
}
}
return session
}

View File

@ -18,6 +18,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/casdoor/casdoor/pp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/xorm-io/core" "github.com/xorm-io/core"
) )
@ -27,43 +29,44 @@ type Payment struct {
Name string `xorm:"varchar(100) notnull pk" json:"name"` Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"` DisplayName string `xorm:"varchar(100)" json:"displayName"`
// Payment Provider Info
Provider string `xorm:"varchar(100)" json:"provider"` Provider string `xorm:"varchar(100)" json:"provider"`
Type string `xorm:"varchar(100)" json:"type"` Type string `xorm:"varchar(100)" json:"type"`
Organization string `xorm:"varchar(100)" json:"organization"` // Product Info
User string `xorm:"varchar(100)" json:"user"`
ProductName string `xorm:"varchar(100)" json:"productName"` ProductName string `xorm:"varchar(100)" json:"productName"`
ProductDisplayName string `xorm:"varchar(100)" json:"productDisplayName"` ProductDisplayName string `xorm:"varchar(100)" json:"productDisplayName"`
Detail string `xorm:"varchar(255)" json:"detail"` Detail string `xorm:"varchar(255)" json:"detail"`
Tag string `xorm:"varchar(100)" json:"tag"` Tag string `xorm:"varchar(100)" json:"tag"`
Currency string `xorm:"varchar(100)" json:"currency"` Currency string `xorm:"varchar(100)" json:"currency"`
Price float64 `json:"price"` Price float64 `json:"price"`
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"` ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
State string `xorm:"varchar(100)" json:"state"` // Payer Info
Message string `xorm:"varchar(2000)" json:"message"` User string `xorm:"varchar(100)" json:"user"`
PersonName string `xorm:"varchar(100)" json:"personName"` PersonName string `xorm:"varchar(100)" json:"personName"`
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"` PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
PersonEmail string `xorm:"varchar(100)" json:"personEmail"` PersonEmail string `xorm:"varchar(100)" json:"personEmail"`
PersonPhone string `xorm:"varchar(100)" json:"personPhone"` PersonPhone string `xorm:"varchar(100)" json:"personPhone"`
// Invoice Info
InvoiceType string `xorm:"varchar(100)" json:"invoiceType"` InvoiceType string `xorm:"varchar(100)" json:"invoiceType"`
InvoiceTitle string `xorm:"varchar(100)" json:"invoiceTitle"` InvoiceTitle string `xorm:"varchar(100)" json:"invoiceTitle"`
InvoiceTaxId string `xorm:"varchar(100)" json:"invoiceTaxId"` InvoiceTaxId string `xorm:"varchar(100)" json:"invoiceTaxId"`
InvoiceRemark string `xorm:"varchar(100)" json:"invoiceRemark"` InvoiceRemark string `xorm:"varchar(100)" json:"invoiceRemark"`
InvoiceUrl string `xorm:"varchar(255)" json:"invoiceUrl"` InvoiceUrl string `xorm:"varchar(255)" json:"invoiceUrl"`
// Order Info
OutOrderId string `xorm:"varchar(100)" json:"outOrderId"`
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
State pp.PaymentState `xorm:"varchar(100)" json:"state"`
Message string `xorm:"varchar(2000)" json:"message"`
} }
func GetPaymentCount(owner, organization, field, value string) (int64, error) { func GetPaymentCount(owner, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "") session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&Payment{Organization: organization}) return session.Count(&Payment{Owner: owner})
} }
func GetPayments(owner string) ([]*Payment, error) { func GetPayments(owner string) ([]*Payment, error) {
payments := []*Payment{} payments := []*Payment{}
err := adapter.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -71,9 +74,9 @@ func GetPayments(owner string) ([]*Payment, error) {
return payments, nil return payments, nil
} }
func GetUserPayments(owner string, organization string, user string) ([]*Payment, error) { func GetUserPayments(owner, user string) ([]*Payment, error) {
payments := []*Payment{} payments := []*Payment{}
err := adapter.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner, Organization: organization, User: user}) err := ormer.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner, User: user})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -81,10 +84,10 @@ func GetUserPayments(owner string, organization string, user string) ([]*Payment
return payments, nil return payments, nil
} }
func GetPaginationPayments(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Payment, error) { func GetPaginationPayments(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Payment, error) {
payments := []*Payment{} payments := []*Payment{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&payments, &Payment{Organization: organization}) err := session.Find(&payments, &Payment{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -98,7 +101,7 @@ func getPayment(owner string, name string) (*Payment, error) {
} }
payment := Payment{Owner: owner, Name: name} payment := Payment{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&payment) existed, err := ormer.Engine.Get(&payment)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -123,16 +126,16 @@ func UpdatePayment(id string, payment *Payment) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(payment) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(payment)
if err != nil { if err != nil {
panic(err) return false, err
} }
return affected != 0, nil return affected != 0, nil
} }
func AddPayment(payment *Payment) (bool, error) { func AddPayment(payment *Payment) (bool, error) {
affected, err := adapter.Engine.Insert(payment) affected, err := ormer.Engine.Insert(payment)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -141,7 +144,7 @@ func AddPayment(payment *Payment) (bool, error) {
} }
func DeletePayment(payment *Payment) (bool, error) { func DeletePayment(payment *Payment) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{payment.Owner, payment.Name}).Delete(&Payment{}) affected, err := ormer.Engine.ID(core.PK{payment.Owner, payment.Name}).Delete(&Payment{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -149,73 +152,76 @@ func DeletePayment(payment *Payment) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func notifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string, orderId string) (*Payment, error, string) { func notifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, *pp.NotifyResult, error) {
provider, err := getProvider(owner, providerName)
if err != nil {
panic(err)
}
pProvider, cert, err := provider.getPaymentProvider()
if err != nil {
panic(err)
}
payment, err := getPayment(owner, paymentName) payment, err := getPayment(owner, paymentName)
if err != nil { if err != nil {
panic(err) return nil, nil, err
} }
if payment == nil { if payment == nil {
err = fmt.Errorf("the payment: %s does not exist", paymentName) err = fmt.Errorf("the payment: %s does not exist", paymentName)
return nil, err, pProvider.GetResponseError(err) return nil, nil, err
} }
product, err := getProduct(owner, productName) provider, err := getProvider(owner, payment.Provider)
if err != nil { if err != nil {
panic(err) return nil, nil, err
}
pProvider, cert, err := provider.getPaymentProvider()
if err != nil {
return nil, nil, err
} }
product, err := getProduct(owner, payment.ProductName)
if err != nil {
return nil, nil, err
}
if product == nil { if product == nil {
err = fmt.Errorf("the product: %s does not exist", productName) err = fmt.Errorf("the product: %s does not exist", payment.ProductName)
return payment, err, pProvider.GetResponseError(err) return nil, nil, err
} }
productDisplayName, paymentName, price, productName, providerName, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId) if orderId == "" {
orderId = payment.OutOrderId
}
notifyResult, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId)
if err != nil { if err != nil {
return payment, err, pProvider.GetResponseError(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 {
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", notifyResult.ProductDisplayName, product.DisplayName)
return payment, nil, err
} }
if productDisplayName != "" && productDisplayName != product.DisplayName { if notifyResult.Price != product.Price {
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", productDisplayName, product.DisplayName) err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", notifyResult.Price, product.Price)
return payment, err, pProvider.GetResponseError(err) return payment, nil, err
} }
if price != product.Price { return payment, notifyResult, nil
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", price, product.Price)
return payment, err, pProvider.GetResponseError(err)
} }
err = nil func NotifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, error) {
return payment, err, pProvider.GetResponseError(err) payment, notifyResult, err := notifyPayment(request, body, owner, paymentName, orderId)
}
func NotifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string, orderId string) (error, string) {
payment, err, errorResponse := notifyPayment(request, body, owner, providerName, productName, paymentName, orderId)
if payment != nil { if payment != nil {
if err != nil { if err != nil {
payment.State = "Error" payment.State = pp.PaymentStateError
payment.Message = err.Error() payment.Message = err.Error()
} else { } else {
payment.State = "Paid" payment.State = notifyResult.PaymentStatus
payment.Message = notifyResult.NotifyMessage
} }
_, err = UpdatePayment(payment.GetId(), payment) _, err = UpdatePayment(payment.GetId(), payment)
if err != nil { if err != nil {
panic(err) return nil, err
} }
} }
return err, errorResponse return payment, nil
} }
func invoicePayment(payment *Payment) (string, error) { func invoicePayment(payment *Payment) (string, error) {
@ -242,7 +248,7 @@ func invoicePayment(payment *Payment) (string, error) {
} }
func InvoicePayment(payment *Payment) (string, error) { func InvoicePayment(payment *Payment) (string, error) {
if payment.State != "Paid" { if payment.State != pp.PaymentStatePaid {
return "", fmt.Errorf("the payment state is supposed to be: \"%s\", got: \"%s\"", "Paid", payment.State) return "", fmt.Errorf("the payment state is supposed to be: \"%s\", got: \"%s\"", "Paid", payment.State)
} }

View File

@ -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)
@ -74,7 +71,7 @@ func GetPermissionCount(owner, field, value string) (int64, error) {
func GetPermissions(owner string) ([]*Permission, error) { func GetPermissions(owner string) ([]*Permission, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner})
if err != nil { if err != nil {
return permissions, err return permissions, err
} }
@ -99,7 +96,7 @@ func getPermission(owner string, name string) (*Permission, error) {
} }
permission := Permission{Owner: owner, Name: name} permission := Permission{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&permission) existed, err := ormer.Engine.Get(&permission)
if err != nil { if err != nil {
return &permission, err return &permission, err
} }
@ -112,7 +109,7 @@ func getPermission(owner string, name string) (*Permission, error) {
} }
func GetPermission(id string) (*Permission, error) { func GetPermission(id string) (*Permission, error) {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
return getPermission(owner, name) return getPermission(owner, name)
} }
@ -149,13 +146,13 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
return false, err return false, err
} }
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
oldPermission, err := getPermission(owner, name) oldPermission, err := getPermission(owner, name)
if oldPermission == nil { if oldPermission == nil {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(permission)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -164,9 +161,9 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
removeGroupingPolicies(oldPermission) removeGroupingPolicies(oldPermission)
removePolicies(oldPermission) removePolicies(oldPermission)
if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter { if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter {
isEmpty, _ := adapter.Engine.IsTableEmpty(oldPermission.Adapter) isEmpty, _ := ormer.Engine.IsTableEmpty(oldPermission.Adapter)
if isEmpty { if isEmpty {
err = adapter.Engine.DropTables(oldPermission.Adapter) err = ormer.Engine.DropTables(oldPermission.Adapter)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -180,7 +177,7 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
} }
func AddPermission(permission *Permission) (bool, error) { func AddPermission(permission *Permission) (bool, error) {
affected, err := adapter.Engine.Insert(permission) affected, err := ormer.Engine.Insert(permission)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -198,7 +195,7 @@ func AddPermissions(permissions []*Permission) bool {
return false return false
} }
affected, err := adapter.Engine.Insert(permissions) affected, err := ormer.Engine.Insert(permissions)
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "Duplicate entry") { if !strings.Contains(err.Error(), "Duplicate entry") {
panic(err) panic(err)
@ -242,7 +239,7 @@ func AddPermissionsInBatch(permissions []*Permission) bool {
} }
func DeletePermission(permission *Permission) (bool, error) { func DeletePermission(permission *Permission) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{}) affected, err := ormer.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -251,9 +248,9 @@ func DeletePermission(permission *Permission) (bool, error) {
removeGroupingPolicies(permission) removeGroupingPolicies(permission)
removePolicies(permission) removePolicies(permission)
if permission.Adapter != "" && permission.Adapter != "permission_rule" { if permission.Adapter != "" && permission.Adapter != "permission_rule" {
isEmpty, _ := adapter.Engine.IsTableEmpty(permission.Adapter) isEmpty, _ := ormer.Engine.IsTableEmpty(permission.Adapter)
if isEmpty { if isEmpty {
err = adapter.Engine.DropTables(permission.Adapter) err = ormer.Engine.DropTables(permission.Adapter)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -266,7 +263,7 @@ func DeletePermission(permission *Permission) (bool, error) {
func GetPermissionsAndRolesByUser(userId string) ([]*Permission, []*Role, error) { func GetPermissionsAndRolesByUser(userId string) ([]*Permission, []*Role, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Where("users like ?", "%"+userId+"\"%").Find(&permissions) err := ormer.Engine.Where("users like ?", "%"+userId+"\"%").Find(&permissions)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -290,7 +287,7 @@ func GetPermissionsAndRolesByUser(userId string) ([]*Permission, []*Role, error)
for _, role := range roles { for _, role := range roles {
perms := []*Permission{} perms := []*Permission{}
err := adapter.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
} }
@ -310,7 +307,7 @@ func GetPermissionsAndRolesByUser(userId string) ([]*Permission, []*Role, error)
func GetPermissionsByRole(roleId string) ([]*Permission, error) { func GetPermissionsByRole(roleId string) ([]*Permission, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Where("roles like ?", "%"+roleId+"\"%").Find(&permissions) err := ormer.Engine.Where("roles like ?", "%"+roleId+"\"%").Find(&permissions)
if err != nil { if err != nil {
return permissions, err return permissions, err
} }
@ -320,7 +317,7 @@ func GetPermissionsByRole(roleId string) ([]*Permission, error) {
func GetPermissionsByResource(resourceId string) ([]*Permission, error) { func GetPermissionsByResource(resourceId string) ([]*Permission, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Where("resources like ?", "%"+resourceId+"\"%").Find(&permissions) err := ormer.Engine.Where("resources like ?", "%"+resourceId+"\"%").Find(&permissions)
if err != nil { if err != nil {
return permissions, err return permissions, err
} }
@ -330,7 +327,7 @@ func GetPermissionsByResource(resourceId string) ([]*Permission, error) {
func GetPermissionsBySubmitter(owner string, submitter string) ([]*Permission, error) { func GetPermissionsBySubmitter(owner string, submitter string) ([]*Permission, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Submitter: submitter}) err := ormer.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Submitter: submitter})
if err != nil { if err != nil {
return permissions, err return permissions, err
} }
@ -340,7 +337,7 @@ func GetPermissionsBySubmitter(owner string, submitter string) ([]*Permission, e
func GetPermissionsByModel(owner string, model string) ([]*Permission, error) { func GetPermissionsByModel(owner string, model string) ([]*Permission, error) {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Model: model}) err := ormer.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Model: model})
if err != nil { if err != nil {
return permissions, err return permissions, err
} }

View File

@ -69,7 +69,7 @@ func getPermissionEnforcer(p *Permission, permissionIDs ...string) *casbin.Enfor
func (p *Permission) setEnforcerAdapter(enforcer *casbin.Enforcer) error { func (p *Permission) setEnforcerAdapter(enforcer *casbin.Enforcer) error {
tableName := "permission_rule" tableName := "permission_rule"
if len(p.Adapter) != 0 { if len(p.Adapter) != 0 {
adapterObj, err := getCasbinAdapter(p.Owner, p.Adapter) adapterObj, err := getAdapter(p.Owner, p.Adapter)
if err != nil { if err != nil {
return err return err
} }
@ -81,12 +81,12 @@ func (p *Permission) setEnforcerAdapter(enforcer *casbin.Enforcer) error {
tableNamePrefix := conf.GetConfigString("tableNamePrefix") tableNamePrefix := conf.GetConfigString("tableNamePrefix")
driverName := conf.GetConfigString("driverName") driverName := conf.GetConfigString("driverName")
dataSourceName := conf.GetConfigRealDataSourceName(driverName) dataSourceName := conf.GetConfigRealDataSourceName(driverName)
casbinAdapter, err := xormadapter.NewAdapterWithTableName(driverName, dataSourceName, tableName, tableNamePrefix, true) adapter, err := xormadapter.NewAdapterWithTableName(driverName, dataSourceName, tableName, tableNamePrefix, true)
if err != nil { if err != nil {
return err return err
} }
enforcer.SetAdapter(casbinAdapter) enforcer.SetAdapter(adapter)
return nil return nil
} }
@ -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-- {

View File

@ -44,7 +44,7 @@ func GetPlanCount(owner, field, value string) (int64, error) {
func GetPlans(owner string) ([]*Plan, error) { func GetPlans(owner string) ([]*Plan, error) {
plans := []*Plan{} plans := []*Plan{}
err := adapter.Engine.Desc("created_time").Find(&plans, &Plan{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&plans, &Plan{Owner: owner})
if err != nil { if err != nil {
return plans, err return plans, err
} }
@ -67,7 +67,7 @@ func getPlan(owner, name string) (*Plan, error) {
} }
plan := Plan{Owner: owner, Name: name} plan := Plan{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&plan) existed, err := ormer.Engine.Get(&plan)
if err != nil { if err != nil {
return &plan, err return &plan, err
} }
@ -91,7 +91,7 @@ func UpdatePlan(id string, plan *Plan) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(plan) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(plan)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -100,7 +100,7 @@ func UpdatePlan(id string, plan *Plan) (bool, error) {
} }
func AddPlan(plan *Plan) (bool, error) { func AddPlan(plan *Plan) (bool, error) {
affected, err := adapter.Engine.Insert(plan) affected, err := ormer.Engine.Insert(plan)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -108,7 +108,7 @@ func AddPlan(plan *Plan) (bool, error) {
} }
func DeletePlan(plan *Plan) (bool, error) { func DeletePlan(plan *Plan) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{plan.Owner, plan.Name}).Delete(plan) affected, err := ormer.Engine.ID(core.PK{plan.Owner, plan.Name}).Delete(plan)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -48,7 +48,7 @@ func GetPricingCount(owner, field, value string) (int64, error) {
func GetPricings(owner string) ([]*Pricing, error) { func GetPricings(owner string) ([]*Pricing, error) {
pricings := []*Pricing{} pricings := []*Pricing{}
err := adapter.Engine.Desc("created_time").Find(&pricings, &Pricing{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&pricings, &Pricing{Owner: owner})
if err != nil { if err != nil {
return pricings, err return pricings, err
} }
@ -72,7 +72,7 @@ func getPricing(owner, name string) (*Pricing, error) {
} }
pricing := Pricing{Owner: owner, Name: name} pricing := Pricing{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&pricing) existed, err := ormer.Engine.Get(&pricing)
if err != nil { if err != nil {
return &pricing, err return &pricing, err
} }
@ -96,7 +96,7 @@ func UpdatePricing(id string, pricing *Pricing) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(pricing) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(pricing)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -105,7 +105,7 @@ func UpdatePricing(id string, pricing *Pricing) (bool, error) {
} }
func AddPricing(pricing *Pricing) (bool, error) { func AddPricing(pricing *Pricing) (bool, error) {
affected, err := adapter.Engine.Insert(pricing) affected, err := ormer.Engine.Insert(pricing)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -113,7 +113,7 @@ func AddPricing(pricing *Pricing) (bool, error) {
} }
func DeletePricing(pricing *Pricing) (bool, error) { func DeletePricing(pricing *Pricing) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{pricing.Owner, pricing.Name}).Delete(pricing) affected, err := ormer.Engine.ID(core.PK{pricing.Owner, pricing.Name}).Delete(pricing)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -17,6 +17,8 @@ package object
import ( import (
"fmt" "fmt"
"github.com/casdoor/casdoor/pp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/xorm-io/core" "github.com/xorm-io/core"
) )
@ -50,7 +52,7 @@ func GetProductCount(owner, field, value string) (int64, error) {
func GetProducts(owner string) ([]*Product, error) { func GetProducts(owner string) ([]*Product, error) {
products := []*Product{} products := []*Product{}
err := adapter.Engine.Desc("created_time").Find(&products, &Product{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&products, &Product{Owner: owner})
if err != nil { if err != nil {
return products, err return products, err
} }
@ -75,7 +77,7 @@ func getProduct(owner string, name string) (*Product, error) {
} }
product := Product{Owner: owner, Name: name} product := Product{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&product) existed, err := ormer.Engine.Get(&product)
if err != nil { if err != nil {
return &product, nil return &product, nil
} }
@ -100,7 +102,7 @@ func UpdateProduct(id string, product *Product) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(product) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(product)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -109,7 +111,7 @@ func UpdateProduct(id string, product *Product) (bool, error) {
} }
func AddProduct(product *Product) (bool, error) { func AddProduct(product *Product) (bool, error) {
affected, err := adapter.Engine.Insert(product) affected, err := ormer.Engine.Insert(product)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -118,7 +120,7 @@ func AddProduct(product *Product) (bool, error) {
} }
func DeleteProduct(product *Product) (bool, error) { func DeleteProduct(product *Product) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{product.Owner, product.Name}).Delete(&Product{}) affected, err := ormer.Engine.ID(core.PK{product.Owner, product.Name}).Delete(&Product{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -183,36 +185,39 @@ func BuyProduct(id string, providerName string, user *User, host string) (string
productDisplayName := product.DisplayName productDisplayName := product.DisplayName
originFrontend, originBackend := getOriginFromHost(host) originFrontend, originBackend := getOriginFromHost(host)
returnUrl := fmt.Sprintf("%s/payments/%s/result", originFrontend, paymentName) returnUrl := fmt.Sprintf("%s/payments/%s/%s/result", originFrontend, owner, paymentName)
notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s/%s/%s", originBackend, owner, providerName, productName, paymentName) notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s", originBackend, owner, paymentName)
// Create an Order and get the payUrl
payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl) payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
// Create a Payment linked with Product and Order
payment := Payment{ payment := Payment{
Owner: product.Owner, Owner: product.Owner,
Name: paymentName, Name: paymentName,
CreatedTime: util.GetCurrentTime(), CreatedTime: util.GetCurrentTime(),
DisplayName: paymentName, DisplayName: paymentName,
Provider: provider.Name, Provider: provider.Name,
Type: provider.Type, Type: provider.Type,
Organization: user.Owner,
User: user.Name,
ProductName: productName, ProductName: productName,
ProductDisplayName: productDisplayName, ProductDisplayName: productDisplayName,
Detail: product.Detail, Detail: product.Detail,
Tag: product.Tag, Tag: product.Tag,
Currency: product.Currency, Currency: product.Currency,
Price: product.Price, Price: product.Price,
PayUrl: payUrl,
ReturnUrl: product.ReturnUrl, ReturnUrl: product.ReturnUrl,
State: "Created",
User: user.Name,
PayUrl: payUrl,
State: pp.PaymentStateCreated,
OutOrderId: orderId,
} }
if provider.Type == "Dummy" { if provider.Type == "Dummy" {
payment.State = "Paid" payment.State = pp.PaymentStatePaid
} }
affected, err := AddPayment(&payment) affected, err := AddPayment(&payment)

View File

@ -119,7 +119,7 @@ func GetGlobalProviderCount(field, value string) (int64, error) {
func GetProviders(owner string) ([]*Provider, error) { func GetProviders(owner string) ([]*Provider, error) {
providers := []*Provider{} providers := []*Provider{}
err := adapter.Engine.Where("owner = ? or owner = ? ", "admin", owner).Desc("created_time").Find(&providers, &Provider{}) err := ormer.Engine.Where("owner = ? or owner = ? ", "admin", owner).Desc("created_time").Find(&providers, &Provider{})
if err != nil { if err != nil {
return providers, err return providers, err
} }
@ -129,7 +129,7 @@ func GetProviders(owner string) ([]*Provider, error) {
func GetGlobalProviders() ([]*Provider, error) { func GetGlobalProviders() ([]*Provider, error) {
providers := []*Provider{} providers := []*Provider{}
err := adapter.Engine.Desc("created_time").Find(&providers) err := ormer.Engine.Desc("created_time").Find(&providers)
if err != nil { if err != nil {
return providers, err return providers, err
} }
@ -165,7 +165,7 @@ func getProvider(owner string, name string) (*Provider, error) {
} }
provider := Provider{Name: name} provider := Provider{Name: name}
existed, err := adapter.Engine.Get(&provider) existed, err := ormer.Engine.Get(&provider)
if err != nil { if err != nil {
return &provider, err return &provider, err
} }
@ -182,20 +182,6 @@ func GetProvider(id string) (*Provider, error) {
return getProvider(owner, name) return getProvider(owner, name)
} }
func getDefaultAiProvider() (*Provider, error) {
provider := Provider{Owner: "admin", Category: "AI"}
existed, err := adapter.Engine.Get(&provider)
if err != nil {
return &provider, err
}
if !existed {
return nil, nil
}
return &provider, nil
}
func GetWechatMiniProgramProvider(application *Application) *Provider { func GetWechatMiniProgramProvider(application *Application) *Provider {
providers := application.Providers providers := application.Providers
for _, provider := range providers { for _, provider := range providers {
@ -217,11 +203,11 @@ 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
} }
} }
session := adapter.Engine.ID(core.PK{owner, name}).AllCols() session := ormer.Engine.ID(core.PK{owner, name}).AllCols()
if provider.ClientSecret == "***" { if provider.ClientSecret == "***" {
session = session.Omit("client_secret") session = session.Omit("client_secret")
} }
@ -248,7 +234,7 @@ func AddProvider(provider *Provider) (bool, error) {
provider.IntranetEndpoint = util.GetEndPoint(provider.IntranetEndpoint) provider.IntranetEndpoint = util.GetEndPoint(provider.IntranetEndpoint)
} }
affected, err := adapter.Engine.Insert(provider) affected, err := ormer.Engine.Insert(provider)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -257,7 +243,7 @@ func AddProvider(provider *Provider) (bool, error) {
} }
func DeleteProvider(provider *Provider) (bool, error) { func DeleteProvider(provider *Provider) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{provider.Owner, provider.Name}).Delete(&Provider{}) affected, err := ormer.Engine.ID(core.PK{provider.Owner, provider.Name}).Delete(&Provider{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -268,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
} }
@ -297,7 +284,7 @@ func (p *Provider) GetId() string {
func GetCaptchaProviderByOwnerName(applicationId, lang string) (*Provider, error) { func GetCaptchaProviderByOwnerName(applicationId, lang string) (*Provider, error) {
owner, name := util.GetOwnerAndNameFromId(applicationId) owner, name := util.GetOwnerAndNameFromId(applicationId)
provider := Provider{Owner: owner, Name: name, Category: "Captcha"} provider := Provider{Owner: owner, Name: name, Category: "Captcha"}
existed, err := adapter.Engine.Get(&provider) existed, err := ormer.Engine.Get(&provider)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -333,7 +320,7 @@ func GetCaptchaProviderByApplication(applicationId, isCurrentProvider, lang stri
} }
func providerChangeTrigger(oldName string, newName string) error { func providerChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -342,7 +329,7 @@ func providerChangeTrigger(oldName string, newName string) error {
} }
var applications []*Application var applications []*Application
err = adapter.Engine.Find(&applications) err = ormer.Engine.Find(&applications)
if err != nil { if err != nil {
return err return err
} }

View File

@ -96,7 +96,7 @@ func AddRecord(record *Record) bool {
fmt.Println(errWebhook) fmt.Println(errWebhook)
} }
affected, err := adapter.Engine.Insert(record) affected, err := ormer.Engine.Insert(record)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -111,7 +111,7 @@ func GetRecordCount(field, value string, filterRecord *Record) (int64, error) {
func GetRecords() ([]*Record, error) { func GetRecords() ([]*Record, error) {
records := []*Record{} records := []*Record{}
err := adapter.Engine.Desc("id").Find(&records) err := ormer.Engine.Desc("id").Find(&records)
if err != nil { if err != nil {
return records, err return records, err
} }
@ -132,7 +132,7 @@ func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder
func GetRecordsByField(record *Record) ([]*Record, error) { func GetRecordsByField(record *Record) ([]*Record, error) {
records := []*Record{} records := []*Record{}
err := adapter.Engine.Find(&records, record) err := ormer.Engine.Find(&records, record)
if err != nil { if err != nil {
return records, err return records, err
} }

View File

@ -46,13 +46,13 @@ func GetResourceCount(owner, user, field, value string) (int64, error) {
} }
func GetResources(owner string, user string) ([]*Resource, error) { func GetResources(owner string, user string) ([]*Resource, error) {
if owner == "built-in" { if owner == "built-in" || owner == "" {
owner = "" owner = ""
user = "" user = ""
} }
resources := []*Resource{} resources := []*Resource{}
err := adapter.Engine.Desc("created_time").Find(&resources, &Resource{Owner: owner, User: user}) err := ormer.Engine.Desc("created_time").Find(&resources, &Resource{Owner: owner, User: user})
if err != nil { if err != nil {
return resources, err return resources, err
} }
@ -61,7 +61,7 @@ func GetResources(owner string, user string) ([]*Resource, error) {
} }
func GetPaginationResources(owner, user string, offset, limit int, field, value, sortField, sortOrder string) ([]*Resource, error) { func GetPaginationResources(owner, user string, offset, limit int, field, value, sortField, sortOrder string) ([]*Resource, error) {
if owner == "built-in" { if owner == "built-in" || owner == "" {
owner = "" owner = ""
user = "" user = ""
} }
@ -82,7 +82,7 @@ func getResource(owner string, name string) (*Resource, error) {
} }
resource := Resource{Owner: owner, Name: name} resource := Resource{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&resource) existed, err := ormer.Engine.Get(&resource)
if err != nil { if err != nil {
return &resource, err return &resource, err
} }
@ -107,7 +107,7 @@ func UpdateResource(id string, resource *Resource) (bool, error) {
return false, nil return false, nil
} }
_, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(resource) _, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(resource)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -117,7 +117,7 @@ func UpdateResource(id string, resource *Resource) (bool, error) {
} }
func AddResource(resource *Resource) (bool, error) { func AddResource(resource *Resource) (bool, error) {
affected, err := adapter.Engine.Insert(resource) affected, err := ormer.Engine.Insert(resource)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -126,7 +126,7 @@ func AddResource(resource *Resource) (bool, error) {
} }
func DeleteResource(resource *Resource) (bool, error) { func DeleteResource(resource *Resource) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{resource.Owner, resource.Name}).Delete(&Resource{}) affected, err := ormer.Engine.ID(core.PK{resource.Owner, resource.Name}).Delete(&Resource{})
if err != nil { if err != nil {
return false, err return false, err
} }

46
object/resource_direct.go Normal file
View File

@ -0,0 +1,46 @@
// 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 object
import (
"strings"
"time"
"github.com/casdoor/casdoor/util"
)
func GetDirectResources(owner string, user string, provider *Provider, prefix string, lang string) ([]*Resource, error) {
storageProvider, err := getStorageProvider(provider, lang)
if err != nil {
return nil, err
}
res := []*Resource{}
objects, err := storageProvider.List(prefix)
for _, obj := range objects {
resource := &Resource{
Owner: owner,
Name: strings.TrimPrefix(obj.Path, "/"),
CreatedTime: obj.LastModified.Local().Format(time.RFC3339),
User: user,
Provider: "",
Application: "",
FileSize: int(obj.Size),
Url: util.UrlJoin(provider.Domain, obj.Path),
}
res = append(res, resource)
}
return res, err
}

View File

@ -44,7 +44,7 @@ func GetRoleCount(owner, field, value string) (int64, error) {
func GetRoles(owner string) ([]*Role, error) { func GetRoles(owner string) ([]*Role, error) {
roles := []*Role{} roles := []*Role{}
err := adapter.Engine.Desc("created_time").Find(&roles, &Role{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&roles, &Role{Owner: owner})
if err != nil { if err != nil {
return roles, err return roles, err
} }
@ -69,7 +69,7 @@ func getRole(owner string, name string) (*Role, error) {
} }
role := Role{Owner: owner, Name: name} role := Role{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&role) existed, err := ormer.Engine.Get(&role)
if err != nil { if err != nil {
return &role, err return &role, err
} }
@ -82,12 +82,12 @@ func getRole(owner string, name string) (*Role, error) {
} }
func GetRole(id string) (*Role, error) { func GetRole(id string) (*Role, error) {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
return getRole(owner, name) return getRole(owner, name)
} }
func UpdateRole(id string, role *Role) (bool, error) { func UpdateRole(id string, role *Role) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
oldRole, err := getRole(owner, name) oldRole, err := getRole(owner, name)
if err != nil { if err != nil {
return false, err return false, err
@ -133,11 +133,11 @@ 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
} }
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(role) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(role)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -178,7 +178,7 @@ func UpdateRole(id string, role *Role) (bool, error) {
} }
func AddRole(role *Role) (bool, error) { func AddRole(role *Role) (bool, error) {
affected, err := adapter.Engine.Insert(role) affected, err := ormer.Engine.Insert(role)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -190,7 +190,7 @@ func AddRoles(roles []*Role) bool {
if len(roles) == 0 { if len(roles) == 0 {
return false return false
} }
affected, err := adapter.Engine.Insert(roles) affected, err := ormer.Engine.Insert(roles)
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "Duplicate entry") { if !strings.Contains(err.Error(), "Duplicate entry") {
panic(err) panic(err)
@ -240,7 +240,7 @@ func DeleteRole(role *Role) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{role.Owner, role.Name}).Delete(&Role{}) affected, err := ormer.Engine.ID(core.PK{role.Owner, role.Name}).Delete(&Role{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -254,7 +254,7 @@ func (role *Role) GetId() string {
func GetRolesByUser(userId string) ([]*Role, error) { func GetRolesByUser(userId string) ([]*Role, error) {
roles := []*Role{} roles := []*Role{}
err := adapter.Engine.Where("users like ?", "%"+userId+"\"%").Find(&roles) err := ormer.Engine.Where("users like ?", "%"+userId+"\"%").Find(&roles)
if err != nil { if err != nil {
return roles, err return roles, err
} }
@ -278,7 +278,7 @@ func GetRolesByUser(userId string) ([]*Role, error) {
} }
func roleChangeTrigger(oldName string, newName string) error { func roleChangeTrigger(oldName string, newName string) error {
session := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -287,7 +287,7 @@ func roleChangeTrigger(oldName string, newName string) error {
} }
var roles []*Role var roles []*Role
err = adapter.Engine.Find(&roles) err = ormer.Engine.Find(&roles)
if err != nil { if err != nil {
return err return err
} }
@ -306,7 +306,7 @@ func roleChangeTrigger(oldName string, newName string) error {
} }
var permissions []*Permission var permissions []*Permission
err = adapter.Engine.Find(&permissions) err = ormer.Engine.Find(&permissions)
if err != nil { if err != nil {
return err return err
} }
@ -338,7 +338,7 @@ func GetMaskedRoles(roles []*Role) []*Role {
func GetRolesByNamePrefix(owner string, prefix string) ([]*Role, error) { func GetRolesByNamePrefix(owner string, prefix string) ([]*Role, error) {
roles := []*Role{} roles := []*Role{}
err := adapter.Engine.Where("owner=? and name like ?", owner, prefix+"%").Find(&roles) err := ormer.Engine.Where("owner=? and name like ?", owner, prefix+"%").Find(&roles)
if err != nil { if err != nil {
return roles, err return roles, err
} }

View File

@ -40,9 +40,9 @@ func GetSessions(owner string) ([]*Session, error) {
sessions := []*Session{} sessions := []*Session{}
var err error var err error
if owner != "" { if owner != "" {
err = adapter.Engine.Desc("created_time").Where("owner = ?", owner).Find(&sessions) err = ormer.Engine.Desc("created_time").Where("owner = ?", owner).Find(&sessions)
} else { } else {
err = adapter.Engine.Desc("created_time").Find(&sessions) err = ormer.Engine.Desc("created_time").Find(&sessions)
} }
if err != nil { if err != nil {
return sessions, err return sessions, err
@ -70,7 +70,7 @@ func GetSessionCount(owner, field, value string) (int64, error) {
func GetSingleSession(id string) (*Session, error) { func GetSingleSession(id string) (*Session, error) {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id) owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
session := Session{Owner: owner, Name: name, Application: application} session := Session{Owner: owner, Name: name, Application: application}
get, err := adapter.Engine.Get(&session) get, err := ormer.Engine.Get(&session)
if err != nil { if err != nil {
return &session, err return &session, err
} }
@ -91,7 +91,7 @@ func UpdateSession(id string, session *Session) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Update(session) affected, err := ormer.Engine.ID(core.PK{owner, name, application}).Update(session)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -114,7 +114,7 @@ func AddSession(session *Session) (bool, error) {
if dbSession == nil { if dbSession == nil {
session.CreatedTime = util.GetCurrentTime() session.CreatedTime = util.GetCurrentTime()
affected, err := adapter.Engine.Insert(session) affected, err := ormer.Engine.Insert(session)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -150,7 +150,7 @@ func DeleteSession(id string) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Delete(&Session{}) affected, err := ormer.Engine.ID(core.PK{owner, name, application}).Delete(&Session{})
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -24,8 +24,10 @@ 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 if provider.Type == "Custom HTTP SMS" {
client, err = newHttpSmsClient(provider.Endpoint, provider.Method, provider.ClientId, provider.Title)
} 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)
} }

75
object/sms_custom.go Normal file
View File

@ -0,0 +1,75 @@
// 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 object
import (
"bytes"
"fmt"
"net/http"
"github.com/casdoor/casdoor/proxy"
)
type HttpSmsClient struct {
endpoint string
method string
paramName string
text string
}
func newHttpSmsClient(endpoint string, method string, paramName string, text string) (*HttpSmsClient, error) {
client := &HttpSmsClient{
endpoint: endpoint,
method: method,
paramName: paramName,
text: text,
}
return client, nil
}
func (c *HttpSmsClient) SendMessage(param map[string]string, targetPhoneNumber ...string) error {
var err error
content := param["code"]
httpClient := proxy.DefaultHttpClient
req, err := http.NewRequest(c.method, c.endpoint, bytes.NewBufferString(content))
if err != nil {
return err
}
if c.method == "POST" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.PostForm = map[string][]string{
c.paramName: {content},
}
} else if c.method == "GET" {
q := req.URL.Query()
q.Add(c.paramName, content)
req.URL.RawQuery = q.Encode()
}
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("SendMessage() error, custom HTTP SMS request failed with status: %s", resp.Status)
}
return err
}

View File

@ -69,7 +69,7 @@ func GetSubscriptionCount(owner, field, value string) (int64, error) {
func GetSubscriptions(owner string) ([]*Subscription, error) { func GetSubscriptions(owner string) ([]*Subscription, error) {
subscriptions := []*Subscription{} subscriptions := []*Subscription{}
err := adapter.Engine.Desc("created_time").Find(&subscriptions, &Subscription{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&subscriptions, &Subscription{Owner: owner})
if err != nil { if err != nil {
return subscriptions, err return subscriptions, err
} }
@ -94,7 +94,7 @@ func getSubscription(owner string, name string) (*Subscription, error) {
} }
subscription := Subscription{Owner: owner, Name: name} subscription := Subscription{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&subscription) existed, err := ormer.Engine.Get(&subscription)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -119,7 +119,7 @@ func UpdateSubscription(id string, subscription *Subscription) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(subscription) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(subscription)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -128,7 +128,7 @@ func UpdateSubscription(id string, subscription *Subscription) (bool, error) {
} }
func AddSubscription(subscription *Subscription) (bool, error) { func AddSubscription(subscription *Subscription) (bool, error) {
affected, err := adapter.Engine.Insert(subscription) affected, err := ormer.Engine.Insert(subscription)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -137,7 +137,7 @@ func AddSubscription(subscription *Subscription) (bool, error) {
} }
func DeleteSubscription(subscription *Subscription) (bool, error) { func DeleteSubscription(subscription *Subscription) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{subscription.Owner, subscription.Name}).Delete(&Subscription{}) affected, err := ormer.Engine.ID(core.PK{subscription.Owner, subscription.Name}).Delete(&Subscription{})
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -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"`
} }
@ -44,7 +45,6 @@ type Syncer struct {
DatabaseType string `xorm:"varchar(100)" json:"databaseType"` DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
Database string `xorm:"varchar(100)" json:"database"` Database string `xorm:"varchar(100)" json:"database"`
Table string `xorm:"varchar(100)" json:"table"` Table string `xorm:"varchar(100)" json:"table"`
TablePrimaryKey string `xorm:"varchar(100)" json:"tablePrimaryKey"`
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"` TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"` AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"` AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"`
@ -53,7 +53,7 @@ type Syncer struct {
IsReadOnly bool `json:"isReadOnly"` IsReadOnly bool `json:"isReadOnly"`
IsEnabled bool `json:"isEnabled"` IsEnabled bool `json:"isEnabled"`
Adapter *Adapter `xorm:"-" json:"-"` Ormer *Ormer `xorm:"-" json:"-"`
} }
func GetSyncerCount(owner, organization, field, value string) (int64, error) { func GetSyncerCount(owner, organization, field, value string) (int64, error) {
@ -63,7 +63,7 @@ func GetSyncerCount(owner, organization, field, value string) (int64, error) {
func GetSyncers(owner string) ([]*Syncer, error) { func GetSyncers(owner string) ([]*Syncer, error) {
syncers := []*Syncer{} syncers := []*Syncer{}
err := adapter.Engine.Desc("created_time").Find(&syncers, &Syncer{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&syncers, &Syncer{Owner: owner})
if err != nil { if err != nil {
return syncers, err return syncers, err
} }
@ -73,7 +73,7 @@ func GetSyncers(owner string) ([]*Syncer, error) {
func GetOrganizationSyncers(owner, organization string) ([]*Syncer, error) { func GetOrganizationSyncers(owner, organization string) ([]*Syncer, error) {
syncers := []*Syncer{} syncers := []*Syncer{}
err := adapter.Engine.Desc("created_time").Find(&syncers, &Syncer{Owner: owner, Organization: organization}) err := ormer.Engine.Desc("created_time").Find(&syncers, &Syncer{Owner: owner, Organization: organization})
if err != nil { if err != nil {
return syncers, err return syncers, err
} }
@ -98,7 +98,7 @@ func getSyncer(owner string, name string) (*Syncer, error) {
} }
syncer := Syncer{Owner: owner, Name: name} syncer := Syncer{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&syncer) existed, err := ormer.Engine.Get(&syncer)
if err != nil { if err != nil {
return &syncer, err return &syncer, err
} }
@ -141,7 +141,7 @@ func UpdateSyncer(id string, syncer *Syncer) (bool, error) {
return false, nil return false, nil
} }
session := adapter.Engine.ID(core.PK{owner, name}).AllCols() session := ormer.Engine.ID(core.PK{owner, name}).AllCols()
if syncer.Password == "***" { if syncer.Password == "***" {
session.Omit("password") session.Omit("password")
} }
@ -172,7 +172,7 @@ func updateSyncerErrorText(syncer *Syncer, line string) (bool, error) {
s.ErrorText = s.ErrorText + line s.ErrorText = s.ErrorText + line
affected, err := adapter.Engine.ID(core.PK{s.Owner, s.Name}).Cols("error_text").Update(s) affected, err := ormer.Engine.ID(core.PK{s.Owner, s.Name}).Cols("error_text").Update(s)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -181,7 +181,7 @@ func updateSyncerErrorText(syncer *Syncer, line string) (bool, error) {
} }
func AddSyncer(syncer *Syncer) (bool, error) { func AddSyncer(syncer *Syncer) (bool, error) {
affected, err := adapter.Engine.Insert(syncer) affected, err := ormer.Engine.Insert(syncer)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -197,7 +197,7 @@ func AddSyncer(syncer *Syncer) (bool, error) {
} }
func DeleteSyncer(syncer *Syncer) (bool, error) { func DeleteSyncer(syncer *Syncer) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{syncer.Owner, syncer.Name}).Delete(&Syncer{}) affected, err := ormer.Engine.ID(core.PK{syncer.Owner, syncer.Name}).Delete(&Syncer{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -229,6 +229,27 @@ func (syncer *Syncer) getTable() string {
} }
} }
func (syncer *Syncer) getKey() string {
key := "id"
hasKey := false
hasId := false
for _, tableColumn := range syncer.TableColumns {
if tableColumn.IsKey {
hasKey = true
key = tableColumn.Name
}
if tableColumn.Name == "id" {
hasId = true
}
}
if !hasKey && !hasId {
key = syncer.TableColumns[0].Name
}
return key
}
func RunSyncer(syncer *Syncer) { func RunSyncer(syncer *Syncer) {
syncer.initAdapter() syncer.initAdapter()
syncer.syncUsers() syncer.syncUsers()

View File

@ -21,7 +21,7 @@ type Affiliation struct {
func (syncer *Syncer) getAffiliations() ([]*Affiliation, error) { func (syncer *Syncer) getAffiliations() ([]*Affiliation, error) {
affiliations := []*Affiliation{} affiliations := []*Affiliation{}
err := syncer.Adapter.Engine.Table(syncer.AffiliationTable).Asc("id").Find(&affiliations) err := syncer.Ormer.Engine.Table(syncer.AffiliationTable).Asc("id").Find(&affiliations)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -20,16 +20,24 @@ import (
) )
func (syncer *Syncer) syncUsers() { func (syncer *Syncer) syncUsers() {
if len(syncer.TableColumns) == 0 {
return
}
fmt.Printf("Running syncUsers()..\n") fmt.Printf("Running syncUsers()..\n")
users, userMap, userNameMap := syncer.getUserMap() users, _, _ := syncer.getUserMap()
oUsers, oUserMap, err := syncer.getOriginalUserMap() oUsers, oUserMap, err := syncer.getOriginalUserMap()
if err != nil { if err != nil {
fmt.Printf(err.Error()) fmt.Printf(err.Error())
timestamp := time.Now().Format("2006-01-02 15:04:05") timestamp := time.Now().Format("2006-01-02 15:04:05")
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error()) line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
updateSyncerErrorText(syncer, line) _, err = updateSyncerErrorText(syncer, line)
if err != nil {
panic(err)
}
return return
} }
@ -40,48 +48,68 @@ func (syncer *Syncer) syncUsers() {
_, affiliationMap, err = syncer.getAffiliationMap() _, affiliationMap, err = syncer.getAffiliationMap()
} }
key := syncer.getKey()
myUsers := map[string]*User{}
for _, m := range users {
myUsers[syncer.getUserValue(m, key)] = m
}
newUsers := []*User{} newUsers := []*User{}
for _, oUser := range oUsers { for _, oUser := range oUsers {
id := oUser.Id primary := syncer.getUserValue(oUser, key)
if _, ok := userMap[id]; !ok {
if _, ok := userNameMap[oUser.Name]; !ok { if _, ok := myUsers[primary]; !ok {
newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
fmt.Printf("New user: %v\n", newUser) fmt.Printf("New user: %v\n", newUser)
newUsers = append(newUsers, newUser) newUsers = append(newUsers, newUser)
}
} else { } else {
user := userMap[id] user := myUsers[primary]
oHash := syncer.calculateHash(oUser) oHash := syncer.calculateHash(oUser)
if user.Hash == user.PreHash { if user.Hash == user.PreHash {
if user.Hash != oHash { if user.Hash != oHash {
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
updatedUser.Hash = oHash updatedUser.Hash = oHash
updatedUser.PreHash = oHash updatedUser.PreHash = oHash
syncer.updateUserForOriginalFields(updatedUser) _, err = syncer.updateUserForOriginalByFields(updatedUser, key)
if err != nil {
panic(err)
}
fmt.Printf("Update from oUser to user: %v\n", updatedUser) fmt.Printf("Update from oUser to user: %v\n", updatedUser)
} }
} else { } else {
if user.PreHash == oHash { if user.PreHash == oHash {
if !syncer.IsReadOnly { if !syncer.IsReadOnly {
updatedOUser := syncer.createOriginalUserFromUser(user) updatedOUser := syncer.createOriginalUserFromUser(user)
syncer.updateUser(updatedOUser) _, err = syncer.updateUser(updatedOUser)
if err != nil {
panic(err)
}
fmt.Printf("Update from user to oUser: %v\n", updatedOUser) fmt.Printf("Update from user to oUser: %v\n", updatedOUser)
} }
// update preHash // update preHash
user.PreHash = user.Hash user.PreHash = user.Hash
SetUserField(user, "pre_hash", user.PreHash) _, err = SetUserField(user, "pre_hash", user.PreHash)
if err != nil {
panic(err)
}
} else { } else {
if user.Hash == oHash { if user.Hash == oHash {
// update preHash // update preHash
user.PreHash = user.Hash user.PreHash = user.Hash
SetUserField(user, "pre_hash", user.PreHash) _, err = SetUserField(user, "pre_hash", user.PreHash)
if err != nil {
panic(err)
}
} else { } else {
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
updatedUser.Hash = oHash updatedUser.Hash = oHash
updatedUser.PreHash = oHash updatedUser.PreHash = oHash
syncer.updateUserForOriginalFields(updatedUser) _, err = syncer.updateUserForOriginalByFields(updatedUser, key)
if err != nil {
panic(err)
}
fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser) fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser)
} }
} }

View File

@ -32,7 +32,7 @@ type Credential struct {
func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) { func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) {
sql := fmt.Sprintf("select * from %s", syncer.getTable()) sql := fmt.Sprintf("select * from %s", syncer.getTable())
results, err := syncer.Adapter.Engine.QueryString(sql) results, err := syncer.Ormer.Engine.QueryString(sql)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -67,7 +67,7 @@ func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
keyString, valueString := syncer.getSqlKeyValueStringFromMap(m) keyString, valueString := syncer.getSqlKeyValueStringFromMap(m)
sql := fmt.Sprintf("insert into %s (%s) values (%s)", syncer.getTable(), keyString, valueString) sql := fmt.Sprintf("insert into %s (%s) values (%s)", syncer.getTable(), keyString, valueString)
res, err := syncer.Adapter.Engine.Exec(sql) res, err := syncer.Ormer.Engine.Exec(sql)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -80,16 +80,6 @@ func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
/*func (syncer *Syncer) getOriginalColumns() []string {
res := []string{}
for _, tableColumn := range syncer.TableColumns {
if tableColumn.CasdoorName != "Id" {
res = append(res, tableColumn.Name)
}
}
return res
}*/
func (syncer *Syncer) getCasdoorColumns() []string { func (syncer *Syncer) getCasdoorColumns() []string {
res := []string{} res := []string{}
for _, tableColumn := range syncer.TableColumns { for _, tableColumn := range syncer.TableColumns {
@ -102,13 +92,15 @@ func (syncer *Syncer) getCasdoorColumns() []string {
} }
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) { func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
key := syncer.getKey()
m := syncer.getMapFromOriginalUser(user) m := syncer.getMapFromOriginalUser(user)
pkValue := m[syncer.TablePrimaryKey] pkValue := m[key]
delete(m, syncer.TablePrimaryKey) delete(m, key)
setString := syncer.getSqlSetStringFromMap(m) setString := syncer.getSqlSetStringFromMap(m)
sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, syncer.TablePrimaryKey, pkValue) sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, key, pkValue)
res, err := syncer.Adapter.Engine.Exec(sql) res, err := syncer.Ormer.Engine.Exec(sql)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -138,7 +130,35 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
columns := syncer.getCasdoorColumns() columns := syncer.getCasdoorColumns()
columns = append(columns, "affiliation", "hash", "pre_hash") columns = append(columns, "affiliation", "hash", "pre_hash")
affected, err := adapter.Engine.ID(core.PK{oldUser.Owner, oldUser.Name}).Cols(columns...).Update(user) affected, err := ormer.Engine.ID(core.PK{oldUser.Owner, oldUser.Name}).Cols(columns...).Update(user)
if err != nil {
return false, err
}
return affected != 0, nil
}
func (syncer *Syncer) updateUserForOriginalByFields(user *User, key string) (bool, error) {
var err error
oldUser := User{}
existed, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(user, key), user.Owner).Get(&oldUser)
if err != nil {
return false, err
}
if !existed {
return false, nil
}
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
user.PermanentAvatar, err = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
if err != nil {
return false, err
}
}
columns := syncer.getCasdoorColumns()
columns = append(columns, "affiliation", "hash", "pre_hash")
affected, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(&oldUser, key), oldUser.Owner).Cols(columns...).Update(user)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -160,7 +180,7 @@ func (syncer *Syncer) calculateHash(user *OriginalUser) string {
} }
func (syncer *Syncer) initAdapter() { func (syncer *Syncer) initAdapter() {
if syncer.Adapter == nil { if syncer.Ormer == nil {
var dataSourceName string var dataSourceName string
if syncer.DatabaseType == "mssql" { if syncer.DatabaseType == "mssql" {
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, syncer.Database) dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, syncer.Database)
@ -174,7 +194,7 @@ func (syncer *Syncer) initAdapter() {
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.") dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
} }
syncer.Adapter = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database) syncer.Ormer = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database)
} }
} }

View File

@ -17,6 +17,7 @@ package object
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -164,6 +165,33 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) {
} }
} }
func (syncer *Syncer) getUserValue(user *User, key string) string {
jsonData, _ := json.Marshal(user)
var mapData map[string]interface{}
if err := json.Unmarshal(jsonData, &mapData); err != nil {
fmt.Println("conversion failed:", err)
return user.Id
}
value := mapData[util.SnakeToCamel(key)]
if str, ok := value.(string); ok {
return str
} else {
if value != nil {
valType := reflect.TypeOf(value)
typeName := valType.Name()
switch typeName {
case "bool":
return strconv.FormatBool(value.(bool))
case "int":
return strconv.Itoa(value.(int))
}
}
return user.Id
}
}
func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*OriginalUser { func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*OriginalUser {
users := []*OriginalUser{} users := []*OriginalUser{}
for _, result := range results { for _, result := range results {
@ -196,7 +224,7 @@ func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*Or
if syncer.Type == "Keycloak" { if syncer.Type == "Keycloak" {
// query and set password and password salt from credential table // query and set password and password salt from credential table
sql := fmt.Sprintf("select * from credential where type = 'password' and user_id = '%s'", originalUser.Id) sql := fmt.Sprintf("select * from credential where type = 'password' and user_id = '%s'", originalUser.Id)
credentialResult, _ := syncer.Adapter.Engine.QueryString(sql) credentialResult, _ := syncer.Ormer.Engine.QueryString(sql)
if len(credentialResult) > 0 { if len(credentialResult) > 0 {
credential := Credential{} credential := Credential{}
_ = json.Unmarshal([]byte(credentialResult[0]["SECRET_DATA"]), &credential) _ = json.Unmarshal([]byte(credentialResult[0]["SECRET_DATA"]), &credential)
@ -206,7 +234,7 @@ func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*Or
// query and set signup application from user group table // query and set signup application from user group table
sql = fmt.Sprintf("select name from keycloak_group where id = "+ sql = fmt.Sprintf("select name from keycloak_group where id = "+
"(select group_id as gid from user_group_membership where user_id = '%s')", originalUser.Id) "(select group_id as gid from user_group_membership where user_id = '%s')", originalUser.Id)
groupResult, _ := syncer.Adapter.Engine.QueryString(sql) groupResult, _ := syncer.Ormer.Engine.QueryString(sql)
if len(groupResult) > 0 { if len(groupResult) > 0 {
originalUser.SignupApplication = groupResult[0]["name"] originalUser.SignupApplication = groupResult[0]["name"]
} }

View File

@ -98,7 +98,7 @@ func GetTokenCount(owner, organization, field, value string) (int64, error) {
func GetTokens(owner string, organization string) ([]*Token, error) { func GetTokens(owner string, organization string) ([]*Token, error) {
tokens := []*Token{} tokens := []*Token{}
err := adapter.Engine.Desc("created_time").Find(&tokens, &Token{Owner: owner, Organization: organization}) err := ormer.Engine.Desc("created_time").Find(&tokens, &Token{Owner: owner, Organization: organization})
return tokens, err return tokens, err
} }
@ -115,7 +115,7 @@ func getToken(owner string, name string) (*Token, error) {
} }
token := Token{Owner: owner, Name: name} token := Token{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&token) existed, err := ormer.Engine.Get(&token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -129,7 +129,7 @@ func getToken(owner string, name string) (*Token, error) {
func getTokenByCode(code string) (*Token, error) { func getTokenByCode(code string) (*Token, error) {
token := Token{Code: code} token := Token{Code: code}
existed, err := adapter.Engine.Get(&token) existed, err := ormer.Engine.Get(&token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -142,7 +142,7 @@ func getTokenByCode(code string) (*Token, error) {
} }
func updateUsedByCode(token *Token) bool { func updateUsedByCode(token *Token) bool {
affected, err := adapter.Engine.Where("code=?", token.Code).Cols("code_is_used").Update(token) affected, err := ormer.Engine.Where("code=?", token.Code).Cols("code_is_used").Update(token)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -167,7 +167,7 @@ func UpdateToken(id string, token *Token) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(token) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(token)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -176,7 +176,7 @@ func UpdateToken(id string, token *Token) (bool, error) {
} }
func AddToken(token *Token) (bool, error) { func AddToken(token *Token) (bool, error) {
affected, err := adapter.Engine.Insert(token) affected, err := ormer.Engine.Insert(token)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -185,7 +185,7 @@ func AddToken(token *Token) (bool, error) {
} }
func DeleteToken(token *Token) (bool, error) { func DeleteToken(token *Token) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{token.Owner, token.Name}).Delete(&Token{}) affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Delete(&Token{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -195,7 +195,7 @@ func DeleteToken(token *Token) (bool, error) {
func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, error) { func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, error) {
token := Token{AccessToken: accessToken} token := Token{AccessToken: accessToken}
existed, err := adapter.Engine.Get(&token) existed, err := ormer.Engine.Get(&token)
if err != nil { if err != nil {
return false, nil, nil, err return false, nil, nil, err
} }
@ -205,7 +205,7 @@ func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, e
} }
token.ExpiresIn = 0 token.ExpiresIn = 0
affected, err := adapter.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(&token) affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(&token)
if err != nil { if err != nil {
return false, nil, nil, err return false, nil, nil, err
} }
@ -221,7 +221,7 @@ func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, e
func GetTokenByAccessToken(accessToken string) (*Token, error) { func GetTokenByAccessToken(accessToken string) (*Token, error) {
// Check if the accessToken is in the database // Check if the accessToken is in the database
token := Token{AccessToken: accessToken} token := Token{AccessToken: accessToken}
existed, err := adapter.Engine.Get(&token) existed, err := ormer.Engine.Get(&token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -235,7 +235,7 @@ func GetTokenByAccessToken(accessToken string) (*Token, error) {
func GetTokenByTokenAndApplication(token string, application string) (*Token, error) { func GetTokenByTokenAndApplication(token string, application string) (*Token, error) {
tokenResult := Token{} tokenResult := Token{}
existed, err := adapter.Engine.Where("(refresh_token = ? or access_token = ? ) and application = ?", token, token, application).Get(&tokenResult) existed, err := ormer.Engine.Where("(refresh_token = ? or access_token = ? ) and application = ?", token, token, application).Get(&tokenResult)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -440,7 +440,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
} }
// check whether the refresh token is valid, and has not expired. // check whether the refresh token is valid, and has not expired.
token := Token{RefreshToken: refreshToken} token := Token{RefreshToken: refreshToken}
existed, err := adapter.Engine.Get(&token) existed, err := ormer.Engine.Get(&token)
if err != nil || !existed { if err != nil || !existed {
return &TokenError{ return &TokenError{
Error: InvalidGrant, Error: InvalidGrant,

View File

@ -29,6 +29,19 @@ const (
UserPropertiesWechatOpenId = "wechatOpenId" UserPropertiesWechatOpenId = "wechatOpenId"
) )
const UserEnforcerId = "built-in/user-enforcer-built-in"
var userEnforcer *UserGroupEnforcer
func InitUserManager() {
enforcer, err := GetInitializedEnforcer(UserEnforcerId)
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"`
@ -157,6 +170,7 @@ type User struct {
Yandex string `xorm:"yandex varchar(100)" json:"yandex"` Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
Zoom string `xorm:"zoom varchar(100)" json:"zoom"` Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
MetaMask string `xorm:"metamask varchar(100)" json:"metamask"` MetaMask string `xorm:"metamask varchar(100)" json:"metamask"`
Web3Onboard string `xorm:"web3onboard varchar(100)" json:"web3onboard"`
Custom string `xorm:"custom varchar(100)" json:"custom"` Custom string `xorm:"custom varchar(100)" json:"custom"`
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"` WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
@ -207,7 +221,7 @@ func GetGlobalUserCount(field, value string) (int64, error) {
func GetGlobalUsers() ([]*User, error) { func GetGlobalUsers() ([]*User, error) {
users := []*User{} users := []*User{}
err := adapter.Engine.Desc("created_time").Find(&users) err := ormer.Engine.Desc("created_time").Find(&users)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -230,19 +244,19 @@ 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{})
} }
func GetOnlineUserCount(owner string, isOnline int) (int64, error) { func GetOnlineUserCount(owner string, isOnline int) (int64, error) {
return adapter.Engine.Where("is_online = ?", isOnline).Count(&User{Owner: owner}) return ormer.Engine.Where("is_online = ?", isOnline).Count(&User{Owner: owner})
} }
func GetUsers(owner string) ([]*User, error) { func GetUsers(owner string) ([]*User, error) {
users := []*User{} users := []*User{}
err := adapter.Engine.Desc("created_time").Find(&users, &User{Owner: owner}) err := ormer.Engine.Desc("created_time").Find(&users, &User{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -252,7 +266,7 @@ func GetUsers(owner string) ([]*User, error) {
func GetUsersByTag(owner string, tag string) ([]*User, error) { func GetUsersByTag(owner string, tag string) ([]*User, error) {
users := []*User{} users := []*User{}
err := adapter.Engine.Desc("created_time").Find(&users, &User{Owner: owner, Tag: tag}) err := ormer.Engine.Desc("created_time").Find(&users, &User{Owner: owner, Tag: tag})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -262,7 +276,7 @@ func GetUsersByTag(owner string, tag string) ([]*User, error) {
func GetSortedUsers(owner string, sorter string, limit int) ([]*User, error) { func GetSortedUsers(owner string, sorter string, limit int) ([]*User, error) {
users := []*User{} users := []*User{}
err := adapter.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &User{Owner: owner}) err := ormer.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &User{Owner: owner})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -274,7 +288,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)
@ -291,7 +305,7 @@ func getUser(owner string, name string) (*User, error) {
} }
user := User{Owner: owner, Name: name} user := User{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -309,7 +323,7 @@ func getUserById(owner string, id string) (*User, error) {
} }
user := User{Owner: owner, Id: id} user := User{Owner: owner, Id: id}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -326,7 +340,7 @@ func getUserByWechatId(owner string, wechatOpenId string, wechatUnionId string)
wechatUnionId = wechatOpenId wechatUnionId = wechatOpenId
} }
user := &User{} user := &User{}
existed, err := adapter.Engine.Where("owner = ?", owner).Where("wechat = ? OR wechat = ?", wechatOpenId, wechatUnionId).Get(user) existed, err := ormer.Engine.Where("owner = ?", owner).Where("wechat = ? OR wechat = ?", wechatOpenId, wechatUnionId).Get(user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -344,7 +358,7 @@ func GetUserByEmail(owner string, email string) (*User, error) {
} }
user := User{Owner: owner, Email: email} user := User{Owner: owner, Email: email}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -362,7 +376,7 @@ func GetUserByPhone(owner string, phone string) (*User, error) {
} }
user := User{Owner: owner, Phone: phone} user := User{Owner: owner, Phone: phone}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -380,7 +394,7 @@ func GetUserByUserId(owner string, userId string) (*User, error) {
} }
user := User{Owner: owner, Id: userId} user := User{Owner: owner, Id: userId}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -397,7 +411,7 @@ func GetUserByAccessKey(accessKey string) (*User, error) {
return nil, nil return nil, nil
} }
user := User{AccessKey: accessKey} user := User{AccessKey: accessKey}
existed, err := adapter.Engine.Get(&user) existed, err := ormer.Engine.Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -471,7 +485,7 @@ func GetMaskedUsers(users []*User, errs ...error) ([]*User, error) {
func GetLastUser(owner string) (*User, error) { func GetLastUser(owner string) (*User, error) {
user := User{Owner: owner} user := User{Owner: owner}
existed, err := adapter.Engine.Desc("created_time", "id").Get(&user) existed, err := ormer.Engine.Desc("created_time", "id").Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -531,6 +545,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
@ -546,7 +567,7 @@ func updateUser(id string, user *User, columns []string) (int64, error) {
return 0, err return 0, err
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user) affected, err := ormer.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -568,7 +589,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
} }
} }
@ -584,7 +605,7 @@ func UpdateUserForAllFields(id string, user *User) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(user) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(user)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -638,7 +659,7 @@ func AddUser(user *User) (bool, error) {
} }
user.Ranking = int(count + 1) user.Ranking = int(count + 1)
affected, err := adapter.Engine.Insert(user) affected, err := ormer.Engine.Insert(user)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -670,7 +691,7 @@ func AddUsers(users []*User) (bool, error) {
} }
} }
affected, err := adapter.Engine.Insert(users) affected, err := ormer.Engine.Insert(users)
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "Duplicate entry") { if !strings.Contains(err.Error(), "Duplicate entry") {
return false, err return false, err
@ -715,7 +736,7 @@ func DeleteUser(user *User) (bool, error) {
return false, err return false, err
} }
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{}) affected, err := ormer.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -778,8 +799,12 @@ 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 := adapter.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()
err := session.Begin() err := session.Begin()
@ -788,7 +813,7 @@ func userChangeTrigger(oldName string, newName string) error {
} }
var roles []*Role var roles []*Role
err = adapter.Engine.Find(&roles) err = ormer.Engine.Find(&roles)
if err != nil { if err != nil {
return err return err
} }
@ -808,7 +833,7 @@ func userChangeTrigger(oldName string, newName string) error {
} }
var permissions []*Permission var permissions []*Permission
err = adapter.Engine.Find(&permissions) err = ormer.Engine.Find(&permissions)
if err != nil { if err != nil {
return err return err
} }
@ -860,3 +885,11 @@ func AddUserkeys(user *User, isAdmin bool) (bool, error) {
return UpdateUser(user.GetId(), user, []string{}, isAdmin) return UpdateUser(user.GetId(), user, []string{}, isAdmin)
} }
func (user *User) IsApplicationAdmin(application *Application) bool {
if user == nil {
return false
}
return (user.Owner == application.Organization && user.IsAdmin) || user.IsGlobalAdmin
}

View File

@ -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
View 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
}

View File

@ -25,7 +25,7 @@ import (
) )
func updateUserColumn(column string, user *User) bool { func updateUserColumn(column string, user *User) bool {
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Cols(column).Update(user) affected, err := ormer.Engine.ID(core.PK{user.Owner, user.Name}).Cols(column).Update(user)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -30,7 +30,7 @@ func GetUserByField(organizationName string, field string, value string) (*User,
} }
user := User{Owner: organizationName} user := User{Owner: organizationName}
existed, err := adapter.Engine.Where(fmt.Sprintf("%s=?", strings.ToLower(field)), value).Get(&user) existed, err := ormer.Engine.Where(fmt.Sprintf("%s=?", strings.ToLower(field)), value).Get(&user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -95,7 +95,7 @@ func SetUserField(user *User, field string, value string) (bool, error) {
bean[strings.ToLower(field)] = value bean[strings.ToLower(field)] = value
} }
affected, err := adapter.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(bean) affected, err := ormer.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(bean)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -110,7 +110,7 @@ func SetUserField(user *User, field string, value string) (bool, error) {
return false, err return false, err
} }
_, err = adapter.Engine.ID(core.PK{user.Owner, user.Name}).Cols("hash").Update(user) _, err = ormer.Engine.ID(core.PK{user.Owner, user.Name}).Cols("hash").Update(user)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -191,7 +191,7 @@ func ClearUserOAuthProperties(user *User, providerType string) (bool, error) {
} }
} }
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Cols("properties").Update(user) affected, err := ormer.Engine.ID(core.PK{user.Owner, user.Name}).Cols("properties").Update(user)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -66,7 +66,7 @@ func IsAllowSend(user *User, remoteAddr, recordType string) error {
if user != nil { if user != nil {
record.User = user.GetId() record.User = user.GetId()
} }
has, err := adapter.Engine.Desc("created_time").Get(&record) has, err := ormer.Engine.Desc("created_time").Get(&record)
if err != nil { if err != nil {
return err return err
} }
@ -143,7 +143,7 @@ func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordT
record.Time = time.Now().Unix() record.Time = time.Now().Unix()
record.IsUsed = false record.IsUsed = false
_, err := adapter.Engine.Insert(record) _, err := ormer.Engine.Insert(record)
if err != nil { if err != nil {
return err return err
} }
@ -154,7 +154,7 @@ func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordT
func getVerificationRecord(dest string) (*VerificationRecord, error) { func getVerificationRecord(dest string) (*VerificationRecord, error) {
var record VerificationRecord var record VerificationRecord
record.Receiver = dest record.Receiver = dest
has, err := adapter.Engine.Desc("time").Where("is_used = false").Get(&record) has, err := ormer.Engine.Desc("time").Where("is_used = false").Get(&record)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -198,7 +198,7 @@ func DisableVerificationCode(dest string) (err error) {
} }
record.IsUsed = true record.IsUsed = true
_, err = adapter.Engine.ID(core.PK{record.Owner, record.Name}).AllCols().Update(record) _, err = ormer.Engine.ID(core.PK{record.Owner, record.Name}).AllCols().Update(record)
return return
} }

View File

@ -49,7 +49,7 @@ func GetWebhookCount(owner, organization, field, value string) (int64, error) {
func GetWebhooks(owner string, organization string) ([]*Webhook, error) { func GetWebhooks(owner string, organization string) ([]*Webhook, error) {
webhooks := []*Webhook{} webhooks := []*Webhook{}
err := adapter.Engine.Desc("created_time").Find(&webhooks, &Webhook{Owner: owner, Organization: organization}) err := ormer.Engine.Desc("created_time").Find(&webhooks, &Webhook{Owner: owner, Organization: organization})
if err != nil { if err != nil {
return webhooks, err return webhooks, err
} }
@ -70,7 +70,7 @@ func GetPaginationWebhooks(owner, organization string, offset, limit int, field,
func getWebhooksByOrganization(organization string) ([]*Webhook, error) { func getWebhooksByOrganization(organization string) ([]*Webhook, error) {
webhooks := []*Webhook{} webhooks := []*Webhook{}
err := adapter.Engine.Desc("created_time").Find(&webhooks, &Webhook{Organization: organization}) err := ormer.Engine.Desc("created_time").Find(&webhooks, &Webhook{Organization: organization})
if err != nil { if err != nil {
return webhooks, err return webhooks, err
} }
@ -84,7 +84,7 @@ func getWebhook(owner string, name string) (*Webhook, error) {
} }
webhook := Webhook{Owner: owner, Name: name} webhook := Webhook{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&webhook) existed, err := ormer.Engine.Get(&webhook)
if err != nil { if err != nil {
return &webhook, err return &webhook, err
} }
@ -109,7 +109,7 @@ func UpdateWebhook(id string, webhook *Webhook) (bool, error) {
return false, nil return false, nil
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(webhook) affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(webhook)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -118,7 +118,7 @@ func UpdateWebhook(id string, webhook *Webhook) (bool, error) {
} }
func AddWebhook(webhook *Webhook) (bool, error) { func AddWebhook(webhook *Webhook) (bool, error) {
affected, err := adapter.Engine.Insert(webhook) affected, err := ormer.Engine.Insert(webhook)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -127,7 +127,7 @@ func AddWebhook(webhook *Webhook) (bool, error) {
} }
func DeleteWebhook(webhook *Webhook) (bool, error) { func DeleteWebhook(webhook *Webhook) (bool, error) {
affected, err := adapter.Engine.ID(core.PK{webhook.Owner, webhook.Name}).Delete(&Webhook{}) affected, err := ormer.Engine.ID(core.PK{webhook.Owner, webhook.Name}).Delete(&Webhook{})
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -16,7 +16,6 @@ package pp
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
@ -67,10 +66,10 @@ func (pp *AlipayPaymentProvider) Pay(providerName string, productName string, pa
return payUrl, "", nil return payUrl, "", nil
} }
func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) { func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
bm, err := alipay.ParseNotifyToBodyMap(request) bm, err := alipay.ParseNotifyToBodyMap(request)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
providerName := bm.Get("providerName") providerName := bm.Get("providerName")
@ -82,13 +81,21 @@ func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, auth
ok, err := alipay.VerifySignWithCert(authorityPublicKey, bm) ok, err := alipay.VerifySignWithCert(authorityPublicKey, bm)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
if !ok { if !ok {
return "", "", 0, "", "", fmt.Errorf("VerifySignWithCert() failed: %v", ok) return nil, err
} }
notifyResult := &NotifyResult{
return productDisplayName, paymentName, price, productName, providerName, nil ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
PaymentStatus: PaymentStatePaid,
Price: price,
PaymentName: paymentName,
}
return notifyResult, nil
} }
func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) { func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {

View File

@ -31,8 +31,10 @@ func (pp *DummyPaymentProvider) Pay(providerName string, productName string, pay
return payUrl, "", nil return payUrl, "", nil
} }
func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) { func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
return "", "", 0, "", "", nil return &NotifyResult{
PaymentStatus: PaymentStatePaid,
}, nil
} }
func (pp *DummyPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) { func (pp *DummyPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {

View File

@ -216,11 +216,11 @@ func (pp *GcPaymentProvider) Pay(providerName string, productName string, payerN
return payRespInfo.PayUrl, "", nil return payRespInfo.PayUrl, "", nil
} }
func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) { func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
reqBody := GcRequestBody{} reqBody := GcRequestBody{}
m, err := url.ParseQuery(string(body)) m, err := url.ParseQuery(string(body))
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
reqBody.Op = m["op"][0] reqBody.Op = m["op"][0]
@ -232,13 +232,13 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
notifyReqInfoBytes, err := base64.StdEncoding.DecodeString(reqBody.Data) notifyReqInfoBytes, err := base64.StdEncoding.DecodeString(reqBody.Data)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
var notifyRespInfo GcNotifyRespInfo var notifyRespInfo GcNotifyRespInfo
err = json.Unmarshal(notifyReqInfoBytes, &notifyRespInfo) err = json.Unmarshal(notifyReqInfoBytes, &notifyRespInfo)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
providerName := "" providerName := ""
@ -249,10 +249,18 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
price := notifyRespInfo.Amount price := notifyRespInfo.Amount
if notifyRespInfo.OrderState != "1" { if notifyRespInfo.OrderState != "1" {
return "", "", 0, "", "", fmt.Errorf("error order state: %s", notifyRespInfo.OrderDate) return nil, fmt.Errorf("error order state: %s", notifyRespInfo.OrderDate)
} }
notifyResult := &NotifyResult{
return productDisplayName, paymentName, price, productName, providerName, nil ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
Price: price,
PaymentStatus: PaymentStatePaid,
PaymentName: paymentName,
}
return notifyResult, nil
} }
func (pp *GcPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) { func (pp *GcPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {

View File

@ -17,9 +17,12 @@ package pp
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"github.com/casdoor/casdoor/conf"
"github.com/go-pay/gopay" "github.com/go-pay/gopay"
"github.com/go-pay/gopay/paypal" "github.com/go-pay/gopay/paypal"
"github.com/go-pay/gopay/pkg/util" "github.com/go-pay/gopay/pkg/util"
@ -31,8 +34,14 @@ type PaypalPaymentProvider struct {
func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentProvider, error) { func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentProvider, error) {
pp := &PaypalPaymentProvider{} pp := &PaypalPaymentProvider{}
isProd := false
client, err := paypal.NewClient(clientID, secret, false) if conf.GetConfigString("runmode") == "prod" {
isProd = true
}
client, err := paypal.NewClient(clientID, secret, isProd)
//if !isProd {
// client.DebugSwitch = gopay.DebugOn
//}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -42,27 +51,27 @@ func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentPro
} }
func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) { func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
// pp.Client.DebugSwitch = gopay.DebugOn // Set log to terminal stdout // https://github.com/go-pay/gopay/blob/main/doc/paypal.md
priceStr := strconv.FormatFloat(price, 'f', 2, 64) priceStr := strconv.FormatFloat(price, 'f', 2, 64)
var pus []*paypal.PurchaseUnit units := make([]*paypal.PurchaseUnit, 0, 1)
item := &paypal.PurchaseUnit{ unit := &paypal.PurchaseUnit{
ReferenceId: util.GetRandomString(16), ReferenceId: util.GetRandomString(16),
Amount: &paypal.Amount{ Amount: &paypal.Amount{
CurrencyCode: currency, CurrencyCode: currency, // e.g."USD"
Value: priceStr, Value: priceStr, // e.g."100.00"
}, },
Description: joinAttachString([]string{productDisplayName, productName, providerName}), Description: joinAttachString([]string{productDisplayName, productName, providerName}),
} }
pus = append(pus, item) units = append(units, unit)
bm := make(gopay.BodyMap) bm := make(gopay.BodyMap)
bm.Set("intent", "CAPTURE") bm.Set("intent", "CAPTURE")
bm.Set("purchase_units", pus) bm.Set("purchase_units", units)
bm.SetBodyMap("application_context", func(b gopay.BodyMap) { bm.SetBodyMap("application_context", func(b gopay.BodyMap) {
b.Set("brand_name", "Casdoor") b.Set("brand_name", "Casdoor")
b.Set("locale", "en-PT") b.Set("locale", "en-PT")
b.Set("return_url", returnUrl) b.Set("return_url", returnUrl)
b.Set("cancel_url", returnUrl)
}) })
ppRsp, err := pp.Client.CreateOrder(context.Background(), bm) ppRsp, err := pp.Client.CreateOrder(context.Background(), bm)
@ -72,31 +81,84 @@ func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, pa
if ppRsp.Code != paypal.Success { if ppRsp.Code != paypal.Success {
return "", "", errors.New(ppRsp.Error) return "", "", errors.New(ppRsp.Error)
} }
// {"id":"9BR68863NE220374S","status":"CREATED",
// "links":[{"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S","rel":"self","method":"GET"},
// {"href":"https://www.sandbox.paypal.com/checkoutnow?token=9BR68863NE220374S","rel":"approve","method":"GET"},
// {"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S","rel":"update","method":"PATCH"},
// {"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S/capture","rel":"capture","method":"POST"}]}
return ppRsp.Response.Links[1].Href, ppRsp.Response.Id, nil return ppRsp.Response.Links[1].Href, ppRsp.Response.Id, nil
} }
func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) { func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
ppRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil) notifyResult := &NotifyResult{}
captureRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
}
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
case "ORDER_ALREADY_CAPTURED":
// 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
detailRsp, err := pp.Client.OrderDetail(context.Background(), orderId, nil)
if err != nil {
return nil, err
}
if captureRsp.Code != paypal.Success {
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
} }
if ppRsp.Code != paypal.Success {
return "", "", 0, "", "", errors.New(ppRsp.Error)
} }
paymentName := ppRsp.Response.Id paymentName := detailRsp.Response.Id
price, err := strconv.ParseFloat(ppRsp.Response.PurchaseUnits[0].Amount.Value, 64) price, err := strconv.ParseFloat(detailRsp.Response.PurchaseUnits[0].Amount.Value, 64)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
currency := detailRsp.Response.PurchaseUnits[0].Amount.CurrencyCode
productDisplayName, productName, providerName, err := parseAttachString(ppRsp.Response.PurchaseUnits[0].Description) productDisplayName, productName, providerName, err := parseAttachString(detailRsp.Response.PurchaseUnits[0].Description)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
// TODO: status better handler, e.g.`hanging`
var paymentStatus PaymentState
switch detailRsp.Response.Status { // CREATED、SAVED、APPROVED、VOIDED、COMPLETED、PAYER_ACTION_REQUIRED
case "COMPLETED":
paymentStatus = PaymentStatePaid
default:
paymentStatus = PaymentStateError
}
notifyResult = &NotifyResult{
PaymentStatus: paymentStatus,
PaymentName: paymentName,
return productDisplayName, paymentName, price, productName, providerName, nil ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
Price: price,
Currency: currency,
OutOrderId: orderId,
}
return notifyResult, nil
} }
func (pp *PaypalPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) { func (pp *PaypalPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {

View File

@ -14,11 +14,36 @@
package pp package pp
import "net/http" import (
"net/http"
)
type PaymentState string
const (
PaymentStatePaid PaymentState = "Paid"
PaymentStateCreated PaymentState = "Created"
PaymentStateCanceled PaymentState = "Canceled"
PaymentStateError PaymentState = "Error"
)
type NotifyResult struct {
PaymentName string
PaymentStatus PaymentState
NotifyMessage string
ProviderName string
ProductName string
ProductDisplayName string
Price float64
Currency string
OutOrderId string
}
type PaymentProvider interface { type PaymentProvider interface {
Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error)
Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error)
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
GetResponseError(err error) string GetResponseError(err error) string
} }

View File

@ -83,22 +83,22 @@ func (pp *WechatPaymentProvider) Pay(providerName string, productName string, pa
return wxRsp.Response.CodeUrl, "", nil return wxRsp.Response.CodeUrl, "", nil
} }
func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) { func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
notifyReq, err := wechat.V3ParseNotify(request) notifyReq, err := wechat.V3ParseNotify(request)
if err != nil { if err != nil {
panic(err) return nil, err
} }
cert := pp.Client.WxPublicKey() cert := pp.Client.WxPublicKey()
err = notifyReq.VerifySignByPK(cert) err = notifyReq.VerifySignByPK(cert)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
apiKey := string(pp.Client.ApiV3Key) apiKey := string(pp.Client.ApiV3Key)
result, err := notifyReq.DecryptCipherText(apiKey) result, err := notifyReq.DecryptCipherText(apiKey)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
paymentName := result.OutTradeNo paymentName := result.OutTradeNo
@ -106,10 +106,19 @@ func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, auth
productDisplayName, productName, providerName, err := parseAttachString(result.Attach) productDisplayName, productName, providerName, err := parseAttachString(result.Attach)
if err != nil { if err != nil {
return "", "", 0, "", "", err return nil, err
} }
return productDisplayName, paymentName, price, productName, providerName, nil notifyResult := &NotifyResult{
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OutOrderId: orderId,
Price: price,
PaymentStatus: PaymentStatePaid,
PaymentName: paymentName,
}
return notifyResult, nil
} }
func (pp *WechatPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) { func (pp *WechatPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {

View File

@ -69,7 +69,7 @@ func getObject(ctx *context.Context) (string, string) {
// query == "?id=built-in/admin" // query == "?id=built-in/admin"
id := ctx.Input.Query("id") id := ctx.Input.Query("id")
if id != "" { if id != "" {
return util.GetOwnerAndNameFromId(id) return util.GetOwnerAndNameFromIdNoCheck(id)
} }
owner := ctx.Input.Query("owner") owner := ctx.Input.Query("owner")
@ -150,7 +150,7 @@ func getUrlPath(urlPath string) string {
return urlPath return urlPath
} }
func AuthzFilter(ctx *context.Context) { func ApiFilter(ctx *context.Context) {
subOwner, subName := getSubject(ctx) subOwner, subName := getSubject(ctx)
method := ctx.Request.Method method := ctx.Request.Method
urlPath := getUrlPath(ctx.Request.URL.Path) urlPath := getUrlPath(ctx.Request.URL.Path)

View File

@ -13,10 +13,14 @@
// limitations under the License. // limitations under the License.
// Package routers // Package routers
// @APIVersion 1.0.0 // @APIVersion 1.376.1
// @Title Casdoor API // @Title Casdoor RESTful API
// @Description Documentation of Casdoor API // @Description Swagger Docs of Casdoor Backend API
// @Contact admin@casbin.org // @Contact casbin@googlegroups.com
// @SecurityDefinition AccessToken apiKey Authorization header
// @Schemes https,http
// @ExternalDocs Find out more about Casdoor
// @ExternalDocsUrl https://casdoor.org/
package routers package routers
import ( import (
@ -113,12 +117,12 @@ func initAPI() {
beego.Router("/api/add-model", &controllers.ApiController{}, "POST:AddModel") beego.Router("/api/add-model", &controllers.ApiController{}, "POST:AddModel")
beego.Router("/api/delete-model", &controllers.ApiController{}, "POST:DeleteModel") beego.Router("/api/delete-model", &controllers.ApiController{}, "POST:DeleteModel")
beego.Router("/api/get-adapters", &controllers.ApiController{}, "GET:GetCasbinAdapters") beego.Router("/api/get-adapters", &controllers.ApiController{}, "GET:GetAdapters")
beego.Router("/api/get-adapter", &controllers.ApiController{}, "GET:GetCasbinAdapter") beego.Router("/api/get-adapter", &controllers.ApiController{}, "GET:GetAdapter")
beego.Router("/api/update-adapter", &controllers.ApiController{}, "POST:UpdateCasbinAdapter") beego.Router("/api/update-adapter", &controllers.ApiController{}, "POST:UpdateAdapter")
beego.Router("/api/add-adapter", &controllers.ApiController{}, "POST:AddCasbinAdapter") beego.Router("/api/add-adapter", &controllers.ApiController{}, "POST:AddAdapter")
beego.Router("/api/delete-adapter", &controllers.ApiController{}, "POST:DeleteCasbinAdapter") beego.Router("/api/delete-adapter", &controllers.ApiController{}, "POST:DeleteAdapter")
beego.Router("/api/sync-policies", &controllers.ApiController{}, "GET:SyncPolicies") beego.Router("/api/get-policies", &controllers.ApiController{}, "GET:GetPolicies")
beego.Router("/api/update-policy", &controllers.ApiController{}, "POST:UpdatePolicy") beego.Router("/api/update-policy", &controllers.ApiController{}, "POST:UpdatePolicy")
beego.Router("/api/add-policy", &controllers.ApiController{}, "POST:AddPolicy") beego.Router("/api/add-policy", &controllers.ApiController{}, "POST:AddPolicy")
beego.Router("/api/remove-policy", &controllers.ApiController{}, "POST:RemovePolicy") beego.Router("/api/remove-policy", &controllers.ApiController{}, "POST:RemovePolicy")
@ -207,19 +211,6 @@ func initAPI() {
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert") beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert") beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
beego.Router("/api/get-chats", &controllers.ApiController{}, "GET:GetChats")
beego.Router("/api/get-chat", &controllers.ApiController{}, "GET:GetChat")
beego.Router("/api/update-chat", &controllers.ApiController{}, "POST:UpdateChat")
beego.Router("/api/add-chat", &controllers.ApiController{}, "POST:AddChat")
beego.Router("/api/delete-chat", &controllers.ApiController{}, "POST:DeleteChat")
beego.Router("/api/get-messages", &controllers.ApiController{}, "GET:GetMessages")
beego.Router("/api/get-message", &controllers.ApiController{}, "GET:GetMessage")
beego.Router("/api/get-message-answer", &controllers.ApiController{}, "GET:GetMessageAnswer")
beego.Router("/api/update-message", &controllers.ApiController{}, "POST:UpdateMessage")
beego.Router("/api/add-message", &controllers.ApiController{}, "POST:AddMessage")
beego.Router("/api/delete-message", &controllers.ApiController{}, "POST:DeleteMessage")
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions") beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription") beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription") beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
@ -251,24 +242,12 @@ func initAPI() {
beego.Router("/api/update-payment", &controllers.ApiController{}, "POST:UpdatePayment") beego.Router("/api/update-payment", &controllers.ApiController{}, "POST:UpdatePayment")
beego.Router("/api/add-payment", &controllers.ApiController{}, "POST:AddPayment") beego.Router("/api/add-payment", &controllers.ApiController{}, "POST:AddPayment")
beego.Router("/api/delete-payment", &controllers.ApiController{}, "POST:DeletePayment") beego.Router("/api/delete-payment", &controllers.ApiController{}, "POST:DeletePayment")
beego.Router("/api/notify-payment/?:owner/?:provider/?:product/?:payment", &controllers.ApiController{}, "POST:NotifyPayment") beego.Router("/api/notify-payment/?:owner/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment") beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail") beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms") beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
beego.Router("/cas/:organization/:application/serviceValidate", &controllers.RootController{}, "GET:CasServiceValidate")
beego.Router("/cas/:organization/:application/proxyValidate", &controllers.RootController{}, "GET:CasProxyValidate")
beego.Router("/cas/:organization/:application/proxy", &controllers.RootController{}, "GET:CasProxy")
beego.Router("/cas/:organization/:application/validate", &controllers.RootController{}, "GET:CasValidate")
beego.Router("/cas/:organization/:application/p3/serviceValidate", &controllers.RootController{}, "GET:CasP3ServiceAndProxyValidate")
beego.Router("/cas/:organization/:application/p3/proxyValidate", &controllers.RootController{}, "GET:CasP3ServiceAndProxyValidate")
beego.Router("/cas/:organization/:application/samlValidate", &controllers.RootController{}, "POST:SamlValidate")
beego.Router("/api/webauthn/signup/begin", &controllers.ApiController{}, "Get:WebAuthnSignupBegin") beego.Router("/api/webauthn/signup/begin", &controllers.ApiController{}, "Get:WebAuthnSignupBegin")
beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish") beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish")
beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin") beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin")
@ -286,4 +265,16 @@ func initAPI() {
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo") beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
beego.Handler("/api/metrics", promhttp.Handler()) beego.Handler("/api/metrics", promhttp.Handler())
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
beego.Router("/cas/:organization/:application/serviceValidate", &controllers.RootController{}, "GET:CasServiceValidate")
beego.Router("/cas/:organization/:application/proxyValidate", &controllers.RootController{}, "GET:CasProxyValidate")
beego.Router("/cas/:organization/:application/proxy", &controllers.RootController{}, "GET:CasProxy")
beego.Router("/cas/:organization/:application/validate", &controllers.RootController{}, "GET:CasValidate")
beego.Router("/cas/:organization/:application/p3/serviceValidate", &controllers.RootController{}, "GET:CasP3ServiceAndProxyValidate")
beego.Router("/cas/:organization/:application/p3/proxyValidate", &controllers.RootController{}, "GET:CasP3ServiceAndProxyValidate")
beego.Router("/cas/:organization/:application/samlValidate", &controllers.RootController{}, "POST:SamlValidate")
} }

View File

@ -55,24 +55,21 @@ 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"
} }
if !util.FileExist(path) {
return
}
if oldStaticBaseUrl == newStaticBaseUrl { if oldStaticBaseUrl == newStaticBaseUrl {
makeGzipResponse(ctx.ResponseWriter, ctx.Request, path) makeGzipResponse(ctx.ResponseWriter, ctx.Request, path)
} else { } else {
serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path, oldStaticBaseUrl, newStaticBaseUrl) serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path)
} }
} }
func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, old string, new string) { func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string) {
f, err := os.Open(filepath.Clean(name)) f, err := os.Open(filepath.Clean(name))
if err != nil { if err != nil {
panic(err) panic(err)
@ -85,13 +82,9 @@ func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, o
} }
oldContent := util.ReadStringFromPath(name) oldContent := util.ReadStringFromPath(name)
newContent := strings.ReplaceAll(oldContent, old, new) newContent := strings.ReplaceAll(oldContent, oldStaticBaseUrl, newStaticBaseUrl)
http.ServeContent(w, r, d.Name(), d.ModTime(), strings.NewReader(newContent)) http.ServeContent(w, r, d.Name(), d.ModTime(), strings.NewReader(newContent))
_, err = w.Write([]byte(newContent))
if err != nil {
panic(err)
}
} }
type gzipResponseWriter struct { type gzipResponseWriter struct {
@ -105,12 +98,12 @@ func (w gzipResponseWriter) Write(b []byte) (int, error) {
func makeGzipResponse(w http.ResponseWriter, r *http.Request, path string) { func makeGzipResponse(w http.ResponseWriter, r *http.Request, path string) {
if !enableGzip || !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { if !enableGzip || !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
http.ServeFile(w, r, path) serveFileWithReplace(w, r, path)
return return
} }
w.Header().Set("Content-Encoding", "gzip") w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w) gz := gzip.NewWriter(w)
defer gz.Close() defer gz.Close()
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w} gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
http.ServeFile(gzw, r, path) serveFileWithReplace(gzw, r, path)
} }

View File

@ -12,17 +12,20 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package ai package storage
import ( import (
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/oss"
"github.com/sashabaranov/go-openai" "github.com/casdoor/oss/googlecloud"
) )
func getProxyClientFromToken(authToken string) *openai.Client { func NewGoogleCloudStorageProvider(clientId string, clientSecret string, bucket string, endpoint string) oss.StorageInterface {
config := openai.DefaultConfig(authToken) sp, _ := googlecloud.New(&googlecloud.Config{
config.HTTPClient = proxy.ProxyHttpClient AccessID: clientId,
AccessKey: clientSecret,
Bucket: bucket,
Endpoint: endpoint,
})
c := openai.NewClientWithConfig(config) return sp
return c
} }

View File

@ -12,17 +12,21 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package ai package storage
import "github.com/pkoukk/tiktoken-go" import (
"github.com/casdoor/oss"
"github.com/casdoor/oss/qiniu"
)
func getTokenSize(model string, prompt string) (int, error) { func NewQiniuCloudKodoStorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
tkm, err := tiktoken.EncodingForModel(model) sp := qiniu.New(&qiniu.Config{
if err != nil { AccessID: clientId,
return 0, err AccessKey: clientSecret,
} Region: region,
Bucket: bucket,
token := tkm.Encode(prompt, nil, nil) Endpoint: endpoint,
res := len(token) })
return res, nil
return sp
} }

View File

@ -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

View File

@ -1,14 +1,18 @@
{ {
"swagger": "2.0", "swagger": "2.0",
"info": { "info": {
"title": "Casdoor API", "title": "Casdoor RESTful API",
"description": "Documentation of Casdoor API", "description": "Swagger Docs of Casdoor Backend API",
"version": "1.0.0", "version": "1.376.1",
"contact": { "contact": {
"email": "admin@casbin.org" "email": "casbin@googlegroups.com"
} }
}, },
"basePath": "/", "basePath": "/",
"schemes": [
"https",
"http"
],
"paths": { "paths": {
"/.well-known/jwks": { "/.well-known/jwks": {
"get": { "get": {
@ -49,7 +53,7 @@
"Adapter API" "Adapter API"
], ],
"description": "add adapter", "description": "add adapter",
"operationId": "ApiController.AddCasbinAdapter", "operationId": "ApiController.AddAdapter",
"parameters": [ "parameters": [
{ {
"in": "body", "in": "body",
@ -995,7 +999,7 @@
"Adapter API" "Adapter API"
], ],
"description": "delete adapter", "description": "delete adapter",
"operationId": "ApiController.DeleteCasbinAdapter", "operationId": "ApiController.DeleteAdapter",
"parameters": [ "parameters": [
{ {
"in": "body", "in": "body",
@ -1747,7 +1751,7 @@
"Adapter API" "Adapter API"
], ],
"description": "get adapter", "description": "get adapter",
"operationId": "ApiController.GetCasbinAdapter", "operationId": "ApiController.GetAdapter",
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
@ -1773,7 +1777,7 @@
"Adapter API" "Adapter API"
], ],
"description": "get adapters", "description": "get adapters",
"operationId": "ApiController.GetCasbinAdapters", "operationId": "ApiController.GetAdapters",
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
@ -3682,7 +3686,8 @@
"name": "id", "name": "id",
"description": "The id ( owner/name ) of the webhook", "description": "The id ( owner/name ) of the webhook",
"required": true, "required": true,
"type": "string" "type": "string",
"default": "built-in/admin"
} }
], ],
"responses": { "responses": {
@ -3708,7 +3713,8 @@
"name": "owner", "name": "owner",
"description": "The owner of webhooks", "description": "The owner of webhooks",
"required": true, "required": true,
"type": "string" "type": "string",
"default": "built-in/admin"
} }
], ],
"responses": { "responses": {
@ -3721,7 +3727,12 @@
} }
} }
} }
},
"security": [
{
"test_apiKey": []
} }
]
} }
}, },
"/api/health": { "/api/health": {
@ -4371,7 +4382,7 @@
"Adapter API" "Adapter API"
], ],
"description": "update adapter", "description": "update adapter",
"operationId": "ApiController.UpdateCasbinAdapter", "operationId": "ApiController.UpdateAdapter",
"parameters": [ "parameters": [
{ {
"in": "query", "in": "query",
@ -5170,7 +5181,8 @@
"name": "id", "name": "id",
"description": "The id ( owner/name ) of the webhook", "description": "The id ( owner/name ) of the webhook",
"required": true, "required": true,
"type": "string" "type": "string",
"default": "built-in/admin"
}, },
{ {
"in": "body", "in": "body",
@ -5419,14 +5431,6 @@
} }
}, },
"definitions": { "definitions": {
"1225.0xc000333110.false": {
"title": "false",
"type": "object"
},
"1260.0xc000333140.false": {
"title": "false",
"type": "object"
},
"LaravelResponse": { "LaravelResponse": {
"title": "LaravelResponse", "title": "LaravelResponse",
"type": "object" "type": "object"
@ -5480,10 +5484,16 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/1225.0xc000333110.false" "additionalProperties": {
"description": "support string, struct or []struct",
"type": "string"
}
}, },
"data2": { "data2": {
"$ref": "#/definitions/1260.0xc000333140.false" "additionalProperties": {
"description": "support string, struct or []struct",
"type": "string"
}
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@ -5525,10 +5535,6 @@
"title": "object", "title": "object",
"type": "object" "type": "object"
}, },
"object.\u0026{197582 0xc000ace360 false}": {
"title": "\u0026{197582 0xc000ace360 false}",
"type": "object"
},
"object.AccountItem": { "object.AccountItem": {
"title": "AccountItem", "title": "AccountItem",
"type": "object", "type": "object",
@ -5722,7 +5728,7 @@
"title": "CasbinRequest", "title": "CasbinRequest",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/object.\u0026{197582 0xc000ace360 false}" "$ref": "#/definitions/object.CasbinRequest"
} }
}, },
"object.Cert": { "object.Cert": {
@ -7866,5 +7872,16 @@
"title": "Engine", "title": "Engine",
"type": "object" "type": "object"
} }
},
"securityDefinitions": {
"AccessToken": {
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
},
"externalDocs": {
"description": "Find out more about Casdoor",
"url": "https://casdoor.org/"
} }
} }

View File

@ -1,11 +1,14 @@
swagger: "2.0" swagger: "2.0"
info: info:
title: Casdoor API title: Casdoor RESTful API
description: Documentation of Casdoor API description: Swagger Docs of Casdoor Backend API
version: 1.0.0 version: 1.376.1
contact: contact:
email: admin@casbin.org email: casbin@googlegroups.com
basePath: / basePath: /
schemes:
- https
- http
paths: paths:
/.well-known/jwks: /.well-known/jwks:
get: get:
@ -33,7 +36,7 @@ paths:
tags: tags:
- Adapter API - Adapter API
description: add adapter description: add adapter
operationId: ApiController.AddCasbinAdapter operationId: ApiController.AddAdapter
parameters: parameters:
- in: body - in: body
name: body name: body
@ -644,7 +647,7 @@ paths:
tags: tags:
- Adapter API - Adapter API
description: delete adapter description: delete adapter
operationId: ApiController.DeleteCasbinAdapter operationId: ApiController.DeleteAdapter
parameters: parameters:
- in: body - in: body
name: body name: body
@ -1128,7 +1131,7 @@ paths:
tags: tags:
- Adapter API - Adapter API
description: get adapter description: get adapter
operationId: ApiController.GetCasbinAdapter operationId: ApiController.GetAdapter
parameters: parameters:
- in: query - in: query
name: id name: id
@ -1145,7 +1148,7 @@ paths:
tags: tags:
- Adapter API - Adapter API
description: get adapters description: get adapters
operationId: ApiController.GetCasbinAdapters operationId: ApiController.GetAdapters
parameters: parameters:
- in: query - in: query
name: owner name: owner
@ -2401,6 +2404,7 @@ paths:
description: The id ( owner/name ) of the webhook description: The id ( owner/name ) of the webhook
required: true required: true
type: string type: string
default: built-in/admin
responses: responses:
"200": "200":
description: The Response object description: The Response object
@ -2418,6 +2422,7 @@ paths:
description: The owner of webhooks description: The owner of webhooks
required: true required: true
type: string type: string
default: built-in/admin
responses: responses:
"200": "200":
description: The Response object description: The Response object
@ -2425,6 +2430,8 @@ paths:
type: array type: array
items: items:
$ref: '#/definitions/object.Webhook' $ref: '#/definitions/object.Webhook'
security:
- test_apiKey: []
/api/health: /api/health:
get: get:
tags: tags:
@ -2854,7 +2861,7 @@ paths:
tags: tags:
- Adapter API - Adapter API
description: update adapter description: update adapter
operationId: ApiController.UpdateCasbinAdapter operationId: ApiController.UpdateAdapter
parameters: parameters:
- in: query - in: query
name: id name: id
@ -3381,6 +3388,7 @@ paths:
description: The id ( owner/name ) of the webhook description: The id ( owner/name ) of the webhook
required: true required: true
type: string type: string
default: built-in/admin
- in: body - in: body
name: body name: body
description: The details of the webhook description: The details of the webhook
@ -3541,12 +3549,6 @@ paths:
schema: schema:
$ref: '#/definitions/controllers.Response' $ref: '#/definitions/controllers.Response'
definitions: definitions:
1225.0xc000333110.false:
title: "false"
type: object
1260.0xc000333140.false:
title: "false"
type: object
LaravelResponse: LaravelResponse:
title: LaravelResponse title: LaravelResponse
type: object type: object
@ -3586,9 +3588,13 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/1225.0xc000333110.false' additionalProperties:
description: support string, struct or []struct
type: string
data2: data2:
$ref: '#/definitions/1260.0xc000333140.false' additionalProperties:
description: support string, struct or []struct
type: string
msg: msg:
type: string type: string
name: name:
@ -3615,9 +3621,6 @@ definitions:
object: object:
title: object title: object
type: object type: object
object.&{197582 0xc000ace360 false}:
title: '&{197582 0xc000ace360 false}'
type: object
object.AccountItem: object.AccountItem:
title: AccountItem title: AccountItem
type: object type: object
@ -3749,7 +3752,7 @@ definitions:
title: CasbinRequest title: CasbinRequest
type: array type: array
items: items:
$ref: '#/definitions/object.&{197582 0xc000ace360 false}' $ref: '#/definitions/object.CasbinRequest'
object.Cert: object.Cert:
title: Cert title: Cert
type: object type: object
@ -5192,3 +5195,11 @@ definitions:
xorm.Engine: xorm.Engine:
title: Engine title: Engine
type: object type: object
securityDefinitions:
AccessToken:
type: apiKey
name: Authorization
in: header
externalDocs:
description: Find out more about Casdoor
url: https://casdoor.org/

Some files were not shown because too many files have changed in this diff Show More