forked from casdoor/casdoor
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59b6854ccc | ||
|
|
0daf67c52c | ||
|
|
4b612269ea | ||
|
|
f438d39720 | ||
|
|
f8df200dbf | ||
|
|
cb1b3b767e | ||
|
|
3bec49f16c | ||
|
|
e28344f0e7 | ||
|
|
93fefed6e8 | ||
|
|
ea9abb2f29 | ||
|
|
337a8c357b | ||
|
|
d8cebfbf04 | ||
|
|
91d5039155 | ||
|
|
5996ee8695 | ||
|
|
8c9331932b | ||
|
|
db594e2096 | ||
|
|
b46b79ee44 | ||
|
|
b9dbbca716 | ||
|
|
313cf6d480 | ||
|
|
0548597d04 | ||
|
|
eb8e26748f | ||
|
|
516a23ab1b | ||
|
|
9887d80e55 | ||
|
|
13dd4337a6 | ||
|
|
36c69a6da1 | ||
|
|
3f4a60096a | ||
|
|
b6240fa356 | ||
|
|
d61f06b053 | ||
|
|
6fe785b6a4 | ||
|
|
cccddea67e | ||
|
|
83b8c5477a | ||
|
|
ac0e069f71 | ||
|
|
4b25e56048 | ||
|
|
39740e3d6c | ||
|
|
87c5bf3855 | ||
|
|
c4a28acbd8 | ||
|
|
ee26b896f6 | ||
|
|
4a8cb9535e | ||
|
|
387a22d5f8 | ||
|
|
36cadded1c | ||
|
|
7d130392d9 | ||
|
|
f82c90b901 | ||
|
|
1a08d6514e | ||
|
|
4d5bf09b36 | ||
|
|
f050deada7 | ||
|
|
dee94666e0 | ||
|
|
b84b7d787b | ||
|
|
d425183137 | ||
|
|
ff7fcd277c | ||
|
|
ed5c0b2713 | ||
|
|
eb60e43192 | ||
|
|
d0170532e6 | ||
|
|
7ddb87cdf8 | ||
|
|
fac45f5ac7 | ||
|
|
266d361244 | ||
|
|
b454ab1931 | ||
|
|
ff39b6f186 |
106
.github/workflows/build.yml
vendored
106
.github/workflows/build.yml
vendored
@@ -44,6 +44,12 @@ jobs:
|
||||
cache-dependency-path: ./web/yarn.lock
|
||||
- run: yarn install && CI=false yarn run build
|
||||
working-directory: ./web
|
||||
- name: Upload build artifacts
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: frontend-build-${{ github.run_id }}
|
||||
path: ./web/build
|
||||
|
||||
backend:
|
||||
name: Back-end
|
||||
@@ -146,39 +152,95 @@ jobs:
|
||||
name: cypress-videos
|
||||
path: ./web/cypress/videos
|
||||
|
||||
release-and-push:
|
||||
name: Release And Push
|
||||
tag-release:
|
||||
name: Create Tag
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
|
||||
needs: [ frontend, backend, linter, e2e ]
|
||||
outputs:
|
||||
new-release-published: ${{ steps.semantic.outputs.new_release_published }}
|
||||
new-release-version: ${{ steps.semantic.outputs.new_release_version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create Tag with Semantic Release
|
||||
id: semantic
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
github-release:
|
||||
name: GitHub Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && needs.tag-release.outputs.new-release-published == 'true'
|
||||
needs: [ tag-release ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Free disk space
|
||||
uses: jlumbroso/free-disk-space@v1.3.1
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
swap-storage: true
|
||||
|
||||
- name: Download frontend build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: frontend-build-${{ github.run_id }}
|
||||
path: ./web/build
|
||||
|
||||
- name: Prepare Go caches
|
||||
run: |
|
||||
echo "GOMODCACHE=$RUNNER_TEMP/gomod" >> $GITHUB_ENV
|
||||
echo "GOCACHE=$RUNNER_TEMP/gocache" >> $GITHUB_ENV
|
||||
go clean -cache -modcache -testcache -fuzzcache
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: '~> v2'
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
docker-release:
|
||||
name: Docker Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && needs.tag-release.outputs.new-release-published == 'true'
|
||||
needs: [ tag-release ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: -1
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Fetch Previous version
|
||||
id: get-previous-tag
|
||||
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
|
||||
|
||||
- name: Release
|
||||
run: yarn global add semantic-release@17.4.4 && semantic-release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Fetch Current version
|
||||
id: get-current-tag
|
||||
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
|
||||
|
||||
- name: Decide Should_Push Or Not
|
||||
id: should_push
|
||||
run: |
|
||||
old_version=${{steps.get-previous-tag.outputs.tag}}
|
||||
new_version=${{steps.get-current-tag.outputs.tag }}
|
||||
new_version=${{ needs.tag-release.outputs.new-release-version }}
|
||||
|
||||
old_array=(${old_version//\./ })
|
||||
new_array=(${new_version//\./ })
|
||||
@@ -217,7 +279,7 @@ jobs:
|
||||
target: STANDARD
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
|
||||
tags: casbin/casdoor:${{ needs.tag-release.outputs.new-release-version }},casbin/casdoor:latest
|
||||
|
||||
- name: Push All In One Version to Docker Hub
|
||||
uses: docker/build-push-action@v3
|
||||
@@ -227,7 +289,7 @@ jobs:
|
||||
target: ALLINONE
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
|
||||
tags: casbin/casdoor-all-in-one:${{ needs.tag-release.outputs.new-release-version }},casbin/casdoor-all-in-one:latest
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
if: steps.should_push.outputs.push=='true'
|
||||
@@ -240,8 +302,8 @@ jobs:
|
||||
if: steps.should_push.outputs.push=='true'
|
||||
run: |
|
||||
# Set the appVersion and version of the chart to the current tag
|
||||
sed -i "s/appVersion: .*/appVersion: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
|
||||
sed -i "s/version: .*/version: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
|
||||
sed -i "s/appVersion: .*/appVersion: ${{ needs.tag-release.outputs.new-release-version }}/g" ./charts/casdoor/Chart.yaml
|
||||
sed -i "s/version: .*/version: ${{ needs.tag-release.outputs.new-release-version }}/g" ./charts/casdoor/Chart.yaml
|
||||
|
||||
REGISTRY=oci://registry-1.docker.io/casbin
|
||||
cd charts/casdoor
|
||||
@@ -255,6 +317,6 @@ jobs:
|
||||
git config --global user.name "casbin-bot"
|
||||
git config --global user.email "bot@casbin.org"
|
||||
git add Chart.yaml index.yaml
|
||||
git commit -m "chore(helm): bump helm charts appVersion to ${{steps.get-current-tag.outputs.tag }}"
|
||||
git tag ${{steps.get-current-tag.outputs.tag }}
|
||||
git commit -m "chore(helm): bump helm charts appVersion to ${{ needs.tag-release.outputs.new-release-version }}"
|
||||
git tag ${{ needs.tag-release.outputs.new-release-version }}
|
||||
git push origin HEAD:master --follow-tags
|
||||
|
||||
54
.goreleaser.yaml
Normal file
54
.goreleaser.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
|
||||
# The lines below are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/need to use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
# you may remove this if you don't need go generate
|
||||
#- go generate ./...
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# this name template makes the OS and Arch compatible with the results of `uname`.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- src: 'web/build'
|
||||
dst: './web/build'
|
||||
- src: 'conf/app.conf'
|
||||
dst: './conf/app.conf'
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
14
README.md
14
README.md
@@ -42,20 +42,6 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<sup>Sponsored by</sup>
|
||||
<br>
|
||||
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.casbin.org/img/stytch-white.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://cdn.casbin.org/img/stytch-charcoal.png">
|
||||
<img src="https://cdn.casbin.org/img/stytch-charcoal.png" width="275">
|
||||
</picture>
|
||||
</a><br/>
|
||||
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin"><b>Build auth with fraud prevention, faster.</b><br/> Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.</a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
## Online demo
|
||||
|
||||
- Read-only site: https://door.casdoor.com (any modification operation will fail)
|
||||
|
||||
@@ -71,6 +71,9 @@ p, *, *, GET, /api/get-payment, *, *
|
||||
p, *, *, POST, /api/update-payment, *, *
|
||||
p, *, *, POST, /api/invoice-payment, *, *
|
||||
p, *, *, POST, /api/notify-payment, *, *
|
||||
p, *, *, POST, /api/place-order, *, *
|
||||
p, *, *, POST, /api/cancel-order, *, *
|
||||
p, *, *, POST, /api/pay-order, *, *
|
||||
p, *, *, POST, /api/unlink, *, *
|
||||
p, *, *, POST, /api/set-password, *, *
|
||||
p, *, *, POST, /api/send-verification-code, *, *
|
||||
@@ -129,7 +132,15 @@ p, *, *, GET, /api/faceid-signin-begin, *, *
|
||||
}
|
||||
}
|
||||
|
||||
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string, extraInfo map[string]interface{}) bool {
|
||||
if urlPath == "/api/mcp" {
|
||||
if detailPath, ok := extraInfo["detailPathUrl"].(string); ok {
|
||||
if detailPath == "initialize" || detailPath == "notifications/initialized" || detailPath == "ping" || detailPath == "tools/list" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if conf.IsDemoMode() {
|
||||
if !isAllowedInDemoMode(subOwner, subName, method, urlPath, objOwner, objName) {
|
||||
return false
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -29,7 +29,7 @@ func init() {
|
||||
presetConfigItems := []string{"httpport", "appname"}
|
||||
for _, key := range presetConfigItems {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
err := beego.AppConfig.Set(key, value)
|
||||
err := web.AppConfig.Set(key, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -42,12 +42,13 @@ func GetConfigString(key string) string {
|
||||
return value
|
||||
}
|
||||
|
||||
res := beego.AppConfig.String(key)
|
||||
res, _ := web.AppConfig.String(key)
|
||||
if res == "" {
|
||||
if key == "staticBaseUrl" {
|
||||
res = "https://cdn.casbin.org"
|
||||
} else if key == "logConfig" {
|
||||
res = fmt.Sprintf("{\"filename\": \"logs/%s.log\", \"maxdays\":99999, \"perm\":\"0770\"}", beego.AppConfig.String("appname"))
|
||||
appname, _ := web.AppConfig.String("appname")
|
||||
res = fmt.Sprintf("{\"filename\": \"logs/%s.log\", \"maxdays\":99999, \"perm\":\"0770\"}", appname)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ package conf
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type Quota struct {
|
||||
@@ -34,7 +34,7 @@ func init() {
|
||||
}
|
||||
|
||||
func initQuota() {
|
||||
res := beego.AppConfig.String("quota")
|
||||
res, _ := web.AppConfig.String("quota")
|
||||
if res != "" {
|
||||
err := json.Unmarshal([]byte(res), quota)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestGetConfString(t *testing.T) {
|
||||
os.Setenv("appname", "casbin")
|
||||
os.Setenv("key", "value")
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
err := web.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
|
||||
for _, scenery := range scenarios {
|
||||
@@ -62,7 +62,7 @@ func TestGetConfInt(t *testing.T) {
|
||||
// do some set up job
|
||||
os.Setenv("httpport", "8001")
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
err := web.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
|
||||
for _, scenery := range scenarios {
|
||||
@@ -83,7 +83,7 @@ func TestGetConfBool(t *testing.T) {
|
||||
{"Should be return false", "copyrequestbody", true},
|
||||
}
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
err := web.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
for _, scenery := range scenarios {
|
||||
t.Run(scenery.description, func(t *testing.T) {
|
||||
@@ -102,7 +102,7 @@ func TestGetConfigQuota(t *testing.T) {
|
||||
{"default", &Quota{-1, -1, -1, -1}},
|
||||
}
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
err := web.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
for _, scenery := range scenarios {
|
||||
quota := GetConfigQuota()
|
||||
@@ -118,7 +118,7 @@ func TestGetConfigLogs(t *testing.T) {
|
||||
{"Default log config", `{"adapter":"file", "filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}`},
|
||||
}
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
err := web.LoadAppConfig("ini", "app.conf")
|
||||
assert.Nil(t, err)
|
||||
for _, scenery := range scenarios {
|
||||
quota := GetConfigString("logConfig")
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -80,11 +81,6 @@ type LaravelResponse struct {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /signup [post]
|
||||
func (c *ApiController) Signup() {
|
||||
if c.GetSessionUsername() != "" {
|
||||
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
|
||||
return
|
||||
}
|
||||
|
||||
var authForm form.AuthForm
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
|
||||
if err != nil {
|
||||
@@ -350,7 +346,7 @@ func (c *ApiController) Logout() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID(context.Background()))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -403,7 +399,7 @@ func (c *ApiController) Logout() {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID(context.Background()))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -436,7 +432,8 @@ func (c *ApiController) Logout() {
|
||||
// SsoLogout
|
||||
// @Title SsoLogout
|
||||
// @Tag Login API
|
||||
// @Description logout the current user from all applications
|
||||
// @Description logout the current user from all applications or current session only
|
||||
// @Param logoutAll query string false "Whether to logout from all sessions. Accepted values: 'true', '1', or empty (default: true). Any other value means false."
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /sso-logout [get,post]
|
||||
func (c *ApiController) SsoLogout() {
|
||||
@@ -447,6 +444,11 @@ func (c *ApiController) SsoLogout() {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user wants to logout from all sessions or just current session
|
||||
// Default is true for backward compatibility
|
||||
logoutAll := c.Ctx.Input.Query("logoutAll")
|
||||
logoutAllSessions := logoutAll == "" || logoutAll == "true" || logoutAll == "1"
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
|
||||
@@ -454,37 +456,62 @@ func (c *ApiController) SsoLogout() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.ExpireTokenByUser(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sessions, err := object.GetUserSessions(owner, username)
|
||||
|
||||
currentSessionId := c.Ctx.Input.CruSession.SessionID(context.Background())
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), currentSessionId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var tokens []*object.Token
|
||||
var sessionIds []string
|
||||
for _, session := range sessions {
|
||||
sessionIds = append(sessionIds, session.SessionId...)
|
||||
}
|
||||
object.DeleteBeegoSession(sessionIds)
|
||||
|
||||
_, err = object.DeleteAllUserSessions(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
if logoutAllSessions {
|
||||
// Logout from all sessions: expire all tokens and delete all sessions
|
||||
// Get tokens before expiring them (for session-level logout notification)
|
||||
tokens, err = object.GetTokensByUser(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.ExpireTokenByUser(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sessions, err := object.GetUserSessions(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, session := range sessions {
|
||||
sessionIds = append(sessionIds, session.SessionId...)
|
||||
}
|
||||
object.DeleteBeegoSession(sessionIds)
|
||||
|
||||
_, err = object.DeleteAllUserSessions(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
util.LogInfo(c.Ctx, "API: [%s] logged out from all applications", user)
|
||||
} else {
|
||||
// Logout from current session only
|
||||
sessionIds = []string{currentSessionId}
|
||||
|
||||
// Only delete the current session's Beego session
|
||||
object.DeleteBeegoSession(sessionIds)
|
||||
|
||||
util.LogInfo(c.Ctx, "API: [%s] logged out from current session", user)
|
||||
}
|
||||
|
||||
// Send SSO logout notifications to all notification providers in the user's signup application
|
||||
// Now includes session-level information for targeted logout
|
||||
userObj, err := object.GetUser(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -492,15 +519,13 @@ func (c *ApiController) SsoLogout() {
|
||||
}
|
||||
|
||||
if userObj != nil {
|
||||
err = object.SendSsoLogoutNotifications(userObj)
|
||||
err = object.SendSsoLogoutNotifications(userObj, sessionIds, tokens)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
util.LogInfo(c.Ctx, "API: [%s] logged out from all applications", user)
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
||||
@@ -517,7 +542,7 @@ func (c *ApiController) GetAccount() {
|
||||
return
|
||||
}
|
||||
|
||||
managedAccounts := c.Input().Get("managedAccounts")
|
||||
managedAccounts := c.Ctx.Input.Query("managedAccounts")
|
||||
if managedAccounts == "1" {
|
||||
user, err = object.ExtendManagedAccountsWithUser(user)
|
||||
if err != nil {
|
||||
@@ -635,8 +660,8 @@ func (c *ApiController) GetUserinfo2() {
|
||||
// @router /get-captcha [get]
|
||||
// @Success 200 {object} object.Userinfo The Response object
|
||||
func (c *ApiController) GetCaptcha() {
|
||||
applicationId := c.Input().Get("applicationId")
|
||||
isCurrentProvider := c.Input().Get("isCurrentProvider")
|
||||
applicationId := c.Ctx.Input.Query("applicationId")
|
||||
isCurrentProvider := c.Ctx.Input.Query("isCurrentProvider")
|
||||
|
||||
captchaProvider, err := object.GetCaptchaProviderByApplication(applicationId, isCurrentProvider, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Adapter The Response object
|
||||
// @router /get-adapters [get]
|
||||
func (c *ApiController) GetAdapters() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
adapters, err := object.GetAdapters(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetAdapters() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
adapters, err := object.GetPaginationAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetAdapters() {
|
||||
// @Success 200 {object} object.Adapter The Response object
|
||||
// @router /get-adapter [get]
|
||||
func (c *ApiController) GetAdapter() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
adapter, err := object.GetAdapter(id)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetAdapter() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-adapter [post]
|
||||
func (c *ApiController) UpdateAdapter() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var adapter object.Adapter
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &adapter)
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -32,14 +32,14 @@ import (
|
||||
// @router /get-applications [get]
|
||||
func (c *ApiController) GetApplications() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organization := c.Input().Get("organization")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
var err error
|
||||
if limit == "" || page == "" {
|
||||
var applications []*object.Application
|
||||
@@ -61,7 +61,7 @@ func (c *ApiController) GetApplications() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
application, err := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -82,7 +82,7 @@ func (c *ApiController) GetApplications() {
|
||||
// @router /get-application [get]
|
||||
func (c *ApiController) GetApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
application, err := object.GetApplication(id)
|
||||
if err != nil {
|
||||
@@ -90,7 +90,7 @@ func (c *ApiController) GetApplication() {
|
||||
return
|
||||
}
|
||||
|
||||
if c.Input().Get("withKey") != "" && application != nil && application.Cert != "" {
|
||||
if c.Ctx.Input.Query("withKey") != "" && application != nil && application.Cert != "" {
|
||||
cert, err := object.GetCert(util.GetId(application.Owner, application.Cert))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -125,7 +125,7 @@ func (c *ApiController) GetApplication() {
|
||||
// @router /get-user-application [get]
|
||||
func (c *ApiController) GetUserApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
user, err := object.GetUser(id)
|
||||
if err != nil {
|
||||
@@ -159,14 +159,14 @@ func (c *ApiController) GetUserApplication() {
|
||||
// @router /get-organization-applications [get]
|
||||
func (c *ApiController) GetOrganizationApplications() {
|
||||
userId := c.GetSessionUsername()
|
||||
organization := c.Input().Get("organization")
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if organization == "" {
|
||||
c.ResponseError(c.T("general:Missing parameter") + ": organization")
|
||||
@@ -196,7 +196,7 @@ func (c *ApiController) GetOrganizationApplications() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
applications, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -223,7 +223,7 @@ func (c *ApiController) GetOrganizationApplications() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-application [post]
|
||||
func (c *ApiController) UpdateApplication() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var application object.Application
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
@@ -27,7 +28,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/casdoor/casdoor/captcha"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/form"
|
||||
@@ -151,14 +152,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
||||
resp = &Response{Status: "ok", Msg: "", Data: userId, Data3: user.NeedUpdatePassword}
|
||||
} else if form.Type == ResponseTypeCode {
|
||||
clientId := c.Input().Get("clientId")
|
||||
responseType := c.Input().Get("responseType")
|
||||
redirectUri := c.Input().Get("redirectUri")
|
||||
scope := c.Input().Get("scope")
|
||||
state := c.Input().Get("state")
|
||||
nonce := c.Input().Get("nonce")
|
||||
challengeMethod := c.Input().Get("code_challenge_method")
|
||||
codeChallenge := c.Input().Get("code_challenge")
|
||||
clientId := c.Ctx.Input.Query("clientId")
|
||||
responseType := c.Ctx.Input.Query("responseType")
|
||||
redirectUri := c.Ctx.Input.Query("redirectUri")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
state := c.Ctx.Input.Query("state")
|
||||
nonce := c.Ctx.Input.Query("nonce")
|
||||
challengeMethod := c.Ctx.Input.Query("code_challenge_method")
|
||||
codeChallenge := c.Ctx.Input.Query("code_challenge")
|
||||
|
||||
if challengeMethod != "S256" && challengeMethod != "null" && challengeMethod != "" {
|
||||
c.ResponseError(c.T("auth:Challenge method should be S256"))
|
||||
@@ -180,8 +181,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
if !object.IsGrantTypeValid(form.Type, application.GrantTypes) {
|
||||
resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""}
|
||||
} else {
|
||||
scope := c.Input().Get("scope")
|
||||
nonce := c.Input().Get("nonce")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
nonce := c.Ctx.Input.Query("nonce")
|
||||
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
|
||||
resp = tokenToResponse(token)
|
||||
|
||||
@@ -227,7 +228,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
}
|
||||
} else if form.Type == ResponseTypeCas {
|
||||
// not oauth but CAS SSO protocol
|
||||
service := c.Input().Get("service")
|
||||
service := c.Ctx.Input.Query("service")
|
||||
resp = wrapErrorResponse(nil)
|
||||
if service != "" {
|
||||
st, err := object.GenerateCasToken(userId, service)
|
||||
@@ -246,9 +247,18 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
resp = wrapErrorResponse(fmt.Errorf("unknown response type: %s", form.Type))
|
||||
}
|
||||
|
||||
// if user did not check auto signin
|
||||
if resp.Status == "ok" && !form.AutoSignin {
|
||||
c.setExpireForSession()
|
||||
// For all successful logins, set the session expiration; if auto signin is not checked, cap it at 24 hours.
|
||||
if resp.Status == "ok" {
|
||||
expireInHours := application.CookieExpireInHours
|
||||
|
||||
if expireInHours == 0 {
|
||||
expireInHours = 720
|
||||
}
|
||||
|
||||
if !form.AutoSignin && expireInHours > 24 {
|
||||
expireInHours = 24
|
||||
}
|
||||
c.setExpireForSession(expireInHours)
|
||||
}
|
||||
|
||||
if application.EnableExclusiveSignin {
|
||||
@@ -260,7 +270,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
|
||||
for _, session := range sessions {
|
||||
for _, sid := range session.SessionId {
|
||||
err := beego.GlobalSessions.GetProvider().SessionDestroy(sid)
|
||||
err := web.GlobalSessions.GetProvider().SessionDestroy(context.Background(), sid)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
@@ -274,9 +284,9 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
Owner: user.Owner,
|
||||
Name: user.Name,
|
||||
Application: application.Name,
|
||||
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
|
||||
SessionId: []string{c.Ctx.Input.CruSession.SessionID(context.Background())},
|
||||
|
||||
ExclusiveSignin: true,
|
||||
ExclusiveSignin: application.EnableExclusiveSignin,
|
||||
})
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
@@ -299,14 +309,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /get-app-login [get]
|
||||
func (c *ApiController) GetApplicationLogin() {
|
||||
clientId := c.Input().Get("clientId")
|
||||
responseType := c.Input().Get("responseType")
|
||||
redirectUri := c.Input().Get("redirectUri")
|
||||
scope := c.Input().Get("scope")
|
||||
state := c.Input().Get("state")
|
||||
id := c.Input().Get("id")
|
||||
loginType := c.Input().Get("type")
|
||||
userCode := c.Input().Get("userCode")
|
||||
clientId := c.Ctx.Input.Query("clientId")
|
||||
responseType := c.Ctx.Input.Query("responseType")
|
||||
redirectUri := c.Ctx.Input.Query("redirectUri")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
state := c.Ctx.Input.Query("state")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
loginType := c.Ctx.Input.Query("type")
|
||||
userCode := c.Ctx.Input.Query("userCode")
|
||||
|
||||
var application *object.Application
|
||||
var msg string
|
||||
@@ -417,7 +427,7 @@ func checkMfaEnable(c *ApiController, user *object.User, organization *object.Or
|
||||
}
|
||||
if len(mfaAllowList) >= 1 {
|
||||
c.SetSession("verificationCodeType", verificationType)
|
||||
c.Ctx.Input.CruSession.SessionRelease(c.Ctx.ResponseWriter)
|
||||
c.Ctx.Input.CruSession.SessionRelease(context.Background(), c.Ctx.ResponseWriter)
|
||||
c.ResponseOk(object.NextMfa, mfaAllowList)
|
||||
return true
|
||||
}
|
||||
@@ -454,13 +464,6 @@ func (c *ApiController) Login() {
|
||||
verificationType := ""
|
||||
|
||||
if authForm.Username != "" {
|
||||
if authForm.Type == ResponseTypeLogin {
|
||||
if c.GetSessionUsername() != "" {
|
||||
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var user *object.User
|
||||
if authForm.SigninMethod == "Face ID" {
|
||||
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
|
||||
@@ -1154,8 +1157,8 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
|
||||
func (c *ApiController) GetSamlLogin() {
|
||||
providerId := c.Input().Get("id")
|
||||
relayState := c.Input().Get("relayState")
|
||||
providerId := c.Ctx.Input.Query("id")
|
||||
relayState := c.Ctx.Input.Query("relayState")
|
||||
authURL, method, err := object.GenerateSamlRequest(providerId, relayState, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -1165,8 +1168,8 @@ func (c *ApiController) GetSamlLogin() {
|
||||
}
|
||||
|
||||
func (c *ApiController) HandleSamlLogin() {
|
||||
relayState := c.Input().Get("RelayState")
|
||||
samlResponse := c.Input().Get("SAMLResponse")
|
||||
relayState := c.Ctx.Input.Query("RelayState")
|
||||
samlResponse := c.Ctx.Input.Query("SAMLResponse")
|
||||
decode, err := base64.StdEncoding.DecodeString(relayState)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -1198,9 +1201,9 @@ func (c *ApiController) HandleOfficialAccountEvent() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
signature := c.Input().Get("signature")
|
||||
timestamp := c.Input().Get("timestamp")
|
||||
nonce := c.Input().Get("nonce")
|
||||
signature := c.Ctx.Input.Query("signature")
|
||||
timestamp := c.Ctx.Input.Query("timestamp")
|
||||
nonce := c.Ctx.Input.Query("nonce")
|
||||
var data struct {
|
||||
MsgType string `xml:"MsgType"`
|
||||
Event string `xml:"Event"`
|
||||
@@ -1258,7 +1261,7 @@ func (c *ApiController) HandleOfficialAccountEvent() {
|
||||
// @Param ticket query string true "The eventId of QRCode"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
func (c *ApiController) GetWebhookEventType() {
|
||||
ticket := c.Input().Get("ticket")
|
||||
ticket := c.Ctx.Input.Query("ticket")
|
||||
|
||||
idp.Lock.RLock()
|
||||
_, ok := idp.WechatCacheMap[ticket]
|
||||
@@ -1278,7 +1281,7 @@ func (c *ApiController) GetWebhookEventType() {
|
||||
// @Param id query string true "The id ( owner/name ) of provider"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
func (c *ApiController) GetQRCode() {
|
||||
providerId := c.Input().Get("id")
|
||||
providerId := c.Ctx.Input.Query("id")
|
||||
provider, err := object.GetProvider(providerId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -1306,9 +1309,9 @@ func (c *ApiController) GetQRCode() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /get-captcha-status [get]
|
||||
func (c *ApiController) GetCaptchaStatus() {
|
||||
organization := c.Input().Get("organization")
|
||||
userId := c.Input().Get("userId")
|
||||
applicationName := c.Input().Get("application")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
applicationName := c.Ctx.Input.Query("application")
|
||||
|
||||
application, err := object.GetApplication(fmt.Sprintf("admin/%s", applicationName))
|
||||
if err != nil {
|
||||
@@ -1351,8 +1354,8 @@ func (c *ApiController) Callback() {
|
||||
// @router /device-auth [post]
|
||||
// @Success 200 {object} object.DeviceAuthResponse The Response object
|
||||
func (c *ApiController) DeviceAuth() {
|
||||
clientId := c.Input().Get("client_id")
|
||||
scope := c.Input().Get("scope")
|
||||
clientId := c.Ctx.Input.Query("client_id")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
application, err := object.GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
c.Data["json"] = object.TokenError{
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/logs"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -27,7 +28,7 @@ import (
|
||||
// ApiController
|
||||
// controller for handlers under /api uri
|
||||
type ApiController struct {
|
||||
beego.Controller
|
||||
web.Controller
|
||||
}
|
||||
|
||||
// RootController
|
||||
@@ -168,6 +169,7 @@ func (c *ApiController) GetSessionApplication() *object.Application {
|
||||
func (c *ApiController) ClearUserSession() {
|
||||
c.SetSessionUsername("")
|
||||
c.SetSessionData(nil)
|
||||
_ = c.SessionRegenerateID()
|
||||
}
|
||||
|
||||
func (c *ApiController) ClearTokenSession() {
|
||||
@@ -236,16 +238,19 @@ func (c *ApiController) setMfaUserSession(userId string) {
|
||||
}
|
||||
|
||||
func (c *ApiController) getMfaUserSession() string {
|
||||
userId := c.Ctx.Input.CruSession.Get(object.MfaSessionUserId)
|
||||
userId := c.Ctx.Input.CruSession.Get(context.Background(), object.MfaSessionUserId)
|
||||
if userId == nil {
|
||||
return ""
|
||||
}
|
||||
return userId.(string)
|
||||
}
|
||||
|
||||
func (c *ApiController) setExpireForSession() {
|
||||
func (c *ApiController) setExpireForSession(cookieExpireInHours int64) {
|
||||
timestamp := time.Now().Unix()
|
||||
timestamp += 3600 * 24
|
||||
if cookieExpireInHours == 0 {
|
||||
cookieExpireInHours = 720
|
||||
}
|
||||
timestamp += 3600 * cookieExpireInHours
|
||||
c.SetSessionData(&SessionData{
|
||||
ExpireTime: timestamp,
|
||||
})
|
||||
|
||||
@@ -41,8 +41,8 @@ func queryUnescape(service string) string {
|
||||
}
|
||||
|
||||
func (c *RootController) CasValidate() {
|
||||
ticket := c.Input().Get("ticket")
|
||||
service := c.Input().Get("service")
|
||||
ticket := c.Ctx.Input.Query("ticket")
|
||||
service := c.Ctx.Input.Query("service")
|
||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||
if service == "" || ticket == "" {
|
||||
c.Ctx.Output.Body([]byte("no\n"))
|
||||
@@ -60,8 +60,8 @@ func (c *RootController) CasValidate() {
|
||||
}
|
||||
|
||||
func (c *RootController) CasServiceValidate() {
|
||||
ticket := c.Input().Get("ticket")
|
||||
format := c.Input().Get("format")
|
||||
ticket := c.Ctx.Input.Query("ticket")
|
||||
format := c.Ctx.Input.Query("format")
|
||||
if !strings.HasPrefix(ticket, "ST") {
|
||||
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
||||
}
|
||||
@@ -75,8 +75,8 @@ func (c *RootController) CasProxyValidate() {
|
||||
}
|
||||
|
||||
func (c *RootController) CasP3ServiceValidate() {
|
||||
ticket := c.Input().Get("ticket")
|
||||
format := c.Input().Get("format")
|
||||
ticket := c.Ctx.Input.Query("ticket")
|
||||
format := c.Ctx.Input.Query("format")
|
||||
if !strings.HasPrefix(ticket, "ST") {
|
||||
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
||||
}
|
||||
@@ -84,10 +84,10 @@ func (c *RootController) CasP3ServiceValidate() {
|
||||
}
|
||||
|
||||
func (c *RootController) CasP3ProxyValidate() {
|
||||
ticket := c.Input().Get("ticket")
|
||||
format := c.Input().Get("format")
|
||||
service := c.Input().Get("service")
|
||||
pgtUrl := c.Input().Get("pgtUrl")
|
||||
ticket := c.Ctx.Input.Query("ticket")
|
||||
format := c.Ctx.Input.Query("format")
|
||||
service := c.Ctx.Input.Query("service")
|
||||
pgtUrl := c.Ctx.Input.Query("pgtUrl")
|
||||
|
||||
serviceResponse := object.CasServiceResponse{
|
||||
Xmlns: "http://www.yale.edu/tp/cas",
|
||||
@@ -161,9 +161,9 @@ func (c *RootController) CasP3ProxyValidate() {
|
||||
}
|
||||
|
||||
func (c *RootController) CasProxy() {
|
||||
pgt := c.Input().Get("pgt")
|
||||
targetService := c.Input().Get("targetService")
|
||||
format := c.Input().Get("format")
|
||||
pgt := c.Ctx.Input.Query("pgt")
|
||||
targetService := c.Ctx.Input.Query("targetService")
|
||||
format := c.Ctx.Input.Query("format")
|
||||
if pgt == "" || targetService == "" {
|
||||
c.sendCasProxyResponseErr(InvalidRequest, "pgt and targetService must exist", format)
|
||||
return
|
||||
@@ -200,7 +200,7 @@ func (c *RootController) CasProxy() {
|
||||
|
||||
func (c *RootController) SamlValidate() {
|
||||
c.Ctx.Output.Header("Content-Type", "text/xml; charset=utf-8")
|
||||
target := c.Input().Get("TARGET")
|
||||
target := c.Ctx.Input.Query("TARGET")
|
||||
body := c.Ctx.Input.RequestBody
|
||||
envelopRequest := struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
|
||||
@@ -34,11 +34,11 @@ import (
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /enforce [post]
|
||||
func (c *ApiController) Enforce() {
|
||||
permissionId := c.Input().Get("permissionId")
|
||||
modelId := c.Input().Get("modelId")
|
||||
resourceId := c.Input().Get("resourceId")
|
||||
enforcerId := c.Input().Get("enforcerId")
|
||||
owner := c.Input().Get("owner")
|
||||
permissionId := c.Ctx.Input.Query("permissionId")
|
||||
modelId := c.Ctx.Input.Query("modelId")
|
||||
resourceId := c.Ctx.Input.Query("resourceId")
|
||||
enforcerId := c.Ctx.Input.Query("enforcerId")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
|
||||
params := []string{permissionId, modelId, resourceId, enforcerId, owner}
|
||||
nonEmpty := 0
|
||||
@@ -180,10 +180,10 @@ func (c *ApiController) Enforce() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /batch-enforce [post]
|
||||
func (c *ApiController) BatchEnforce() {
|
||||
permissionId := c.Input().Get("permissionId")
|
||||
modelId := c.Input().Get("modelId")
|
||||
enforcerId := c.Input().Get("enforcerId")
|
||||
owner := c.Input().Get("owner")
|
||||
permissionId := c.Ctx.Input.Query("permissionId")
|
||||
modelId := c.Ctx.Input.Query("modelId")
|
||||
enforcerId := c.Ctx.Input.Query("enforcerId")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
|
||||
params := []string{permissionId, modelId, enforcerId, owner}
|
||||
nonEmpty := 0
|
||||
@@ -304,7 +304,7 @@ func (c *ApiController) BatchEnforce() {
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllObjects() {
|
||||
userId := c.Input().Get("userId")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
if userId == "" {
|
||||
userId = c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
@@ -323,7 +323,7 @@ func (c *ApiController) GetAllObjects() {
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllActions() {
|
||||
userId := c.Input().Get("userId")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
if userId == "" {
|
||||
userId = c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
@@ -342,7 +342,7 @@ func (c *ApiController) GetAllActions() {
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllRoles() {
|
||||
userId := c.Input().Get("userId")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
if userId == "" {
|
||||
userId = c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
|
||||
@@ -169,8 +169,8 @@ func (c *ApiController) RunCasbinCommand() {
|
||||
return
|
||||
}
|
||||
|
||||
language := c.Input().Get("language")
|
||||
argString := c.Input().Get("args")
|
||||
language := c.Ctx.Input.Query("language")
|
||||
argString := c.Ctx.Input.Query("args")
|
||||
|
||||
if language == "" {
|
||||
language = "go"
|
||||
@@ -262,10 +262,10 @@ func (c *ApiController) RunCasbinCommand() {
|
||||
// @Param hash string The SHA-256 hash string
|
||||
// @Return error Returns error if validation fails, nil if successful
|
||||
func validateIdentifier(c *ApiController) error {
|
||||
language := c.Input().Get("language")
|
||||
args := c.Input().Get("args")
|
||||
hash := c.Input().Get("m")
|
||||
timestamp := c.Input().Get("t")
|
||||
language := c.Ctx.Input.Query("language")
|
||||
args := c.Ctx.Input.Query("args")
|
||||
hash := c.Ctx.Input.Query("m")
|
||||
timestamp := c.Ctx.Input.Query("t")
|
||||
|
||||
if hash == "" || timestamp == "" || language == "" || args == "" {
|
||||
return fmt.Errorf("invalid identifier")
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Cert The Response object
|
||||
// @router /get-certs [get]
|
||||
func (c *ApiController) GetCerts() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
certs, err := object.GetMaskedCerts(object.GetCerts(owner))
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetCerts() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
certs, err := object.GetMaskedCerts(object.GetPaginationCerts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -72,12 +72,12 @@ func (c *ApiController) GetCerts() {
|
||||
// @Success 200 {array} object.Cert The Response object
|
||||
// @router /get-global-certs [get]
|
||||
func (c *ApiController) GetGlobalCerts() {
|
||||
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")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
certs, err := object.GetMaskedCerts(object.GetGlobalCerts())
|
||||
@@ -95,7 +95,7 @@ func (c *ApiController) GetGlobalCerts() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
certs, err := object.GetMaskedCerts(object.GetPaginationGlobalCerts(paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -114,7 +114,7 @@ func (c *ApiController) GetGlobalCerts() {
|
||||
// @Success 200 {object} object.Cert The Response object
|
||||
// @router /get-cert [get]
|
||||
func (c *ApiController) GetCert() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
cert, err := object.GetCert(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -133,7 +133,7 @@ func (c *ApiController) GetCert() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-cert [post]
|
||||
func (c *ApiController) UpdateCert() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var cert object.Cert
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -446,13 +446,13 @@ func downloadCLI() error {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /refresh-engines [post]
|
||||
func (c *ApiController) RefreshEngines() {
|
||||
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
if !web.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
c.ResponseError("refresh engines is only available in demo mode")
|
||||
return
|
||||
}
|
||||
|
||||
hash := c.Input().Get("m")
|
||||
timestamp := c.Input().Get("t")
|
||||
hash := c.Ctx.Input.Query("m")
|
||||
timestamp := c.Ctx.Input.Query("t")
|
||||
|
||||
if hash == "" || timestamp == "" {
|
||||
c.ResponseError("invalid identifier")
|
||||
@@ -498,7 +498,7 @@ func (c *ApiController) RefreshEngines() {
|
||||
// @Title ScheduleCLIUpdater
|
||||
// @Description Start periodic CLI update scheduler
|
||||
func ScheduleCLIUpdater() {
|
||||
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
if !web.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ func DownloadCLI() error {
|
||||
// @Title InitCLIDownloader
|
||||
// @Description Initialize CLI downloader and start update scheduler
|
||||
func InitCLIDownloader() {
|
||||
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
if !web.AppConfig.DefaultBool("isDemoMode", false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||
@@ -32,13 +32,13 @@ import (
|
||||
// @Success 200 {array} object.Enforcer
|
||||
// @router /get-enforcers [get]
|
||||
func (c *ApiController) GetEnforcers() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
enforcers, err := object.GetEnforcers(owner)
|
||||
@@ -56,7 +56,7 @@ func (c *ApiController) GetEnforcers() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
enforcers, err := object.GetPaginationEnforcers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -75,8 +75,8 @@ func (c *ApiController) GetEnforcers() {
|
||||
// @Success 200 {object} object.Enforcer
|
||||
// @router /get-enforcer [get]
|
||||
func (c *ApiController) GetEnforcer() {
|
||||
id := c.Input().Get("id")
|
||||
loadModelCfg := c.Input().Get("loadModelCfg")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
loadModelCfg := c.Ctx.Input.Query("loadModelCfg")
|
||||
|
||||
enforcer, err := object.GetEnforcer(id)
|
||||
if err != nil {
|
||||
@@ -105,7 +105,7 @@ func (c *ApiController) GetEnforcer() {
|
||||
// @Success 200 {object} object.Enforcer
|
||||
// @router /update-enforcer [post]
|
||||
func (c *ApiController) UpdateEnforcer() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
enforcer := object.Enforcer{}
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &enforcer)
|
||||
@@ -165,8 +165,8 @@ func (c *ApiController) DeleteEnforcer() {
|
||||
// @Success 200 {array} xormadapter.CasbinRule
|
||||
// @router /get-policies [get]
|
||||
func (c *ApiController) GetPolicies() {
|
||||
id := c.Input().Get("id")
|
||||
adapterId := c.Input().Get("adapterId")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
adapterId := c.Ctx.Input.Query("adapterId")
|
||||
|
||||
if adapterId != "" {
|
||||
adapter, err := object.GetAdapter(adapterId)
|
||||
@@ -207,7 +207,7 @@ func (c *ApiController) GetPolicies() {
|
||||
// @Success 200 {array} xormadapter.CasbinRule
|
||||
// @router /get-filtered-policies [post]
|
||||
func (c *ApiController) GetFilteredPolicies() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var filters []object.Filter
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &filters)
|
||||
@@ -234,7 +234,7 @@ func (c *ApiController) GetFilteredPolicies() {
|
||||
// @Success 200 {object} Response
|
||||
// @router /update-policy [post]
|
||||
func (c *ApiController) UpdatePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var policies []xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
|
||||
@@ -261,7 +261,7 @@ func (c *ApiController) UpdatePolicy() {
|
||||
// @Success 200 {object} Response
|
||||
// @router /add-policy [post]
|
||||
func (c *ApiController) AddPolicy() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var policy xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||
@@ -288,7 +288,7 @@ func (c *ApiController) AddPolicy() {
|
||||
// @Success 200 {object} Response
|
||||
// @router /remove-policy [post]
|
||||
func (c *ApiController) RemovePolicy() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var policy xormadapter.CasbinRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||
|
||||
@@ -33,8 +33,8 @@ import (
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /faceid-signin-begin [get]
|
||||
func (c *ApiController) FaceIDSigninBegin() {
|
||||
userOwner := c.Input().Get("owner")
|
||||
userName := c.Input().Get("name")
|
||||
userOwner := c.Ctx.Input.Query("owner")
|
||||
userName := c.Ctx.Input.Query("name")
|
||||
|
||||
user, err := object.GetUserByFields(userOwner, userName)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -46,13 +46,13 @@ func (c *ApiController) GetGlobalForms() {
|
||||
// @Success 200 {array} object.Form The Response object
|
||||
// @router /get-forms [get]
|
||||
func (c *ApiController) GetForms() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
forms, err := object.GetForms(owner)
|
||||
@@ -70,7 +70,7 @@ func (c *ApiController) GetForms() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
forms, err := object.GetPaginationForms(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -88,7 +88,7 @@ func (c *ApiController) GetForms() {
|
||||
// @Success 200 {object} object.Form The Response object
|
||||
// @router /get-form [get]
|
||||
func (c *ApiController) GetForm() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
form, err := object.GetForm(id)
|
||||
if err != nil {
|
||||
@@ -108,7 +108,7 @@ func (c *ApiController) GetForm() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-form [post]
|
||||
func (c *ApiController) UpdateForm() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var form object.Form
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||
|
||||
@@ -23,7 +23,7 @@ import "github.com/casdoor/casdoor/object"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /get-dashboard [get]
|
||||
func (c *ApiController) GetDashboard() {
|
||||
owner := c.Input().Get("owner")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
|
||||
data, err := object.GetDashboard(owner)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,14 +30,14 @@ import (
|
||||
// @Success 200 {array} object.Group The Response object
|
||||
// @router /get-groups [get]
|
||||
func (c *ApiController) GetGroups() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
withTree := c.Input().Get("withTree")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
withTree := c.Ctx.Input.Query("withTree")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
groups, err := object.GetGroups(owner)
|
||||
@@ -66,7 +66,7 @@ func (c *ApiController) GetGroups() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
groups, err := object.GetPaginationGroups(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -109,7 +109,7 @@ func (c *ApiController) GetGroups() {
|
||||
// @Success 200 {object} object.Group The Response object
|
||||
// @router /get-group [get]
|
||||
func (c *ApiController) GetGroup() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
group, err := object.GetGroup(id)
|
||||
if err != nil {
|
||||
@@ -135,7 +135,7 @@ func (c *ApiController) GetGroup() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-group [post]
|
||||
func (c *ApiController) UpdateGroup() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var group object.Group
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &group)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -32,13 +32,13 @@ import (
|
||||
// @Success 200 {array} object.Invitation The Response object
|
||||
// @router /get-invitations [get]
|
||||
func (c *ApiController) GetInvitations() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
invitations, err := object.GetInvitations(owner)
|
||||
@@ -56,7 +56,7 @@ func (c *ApiController) GetInvitations() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
invitations, err := object.GetPaginationInvitations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -75,7 +75,7 @@ func (c *ApiController) GetInvitations() {
|
||||
// @Success 200 {object} object.Invitation The Response object
|
||||
// @router /get-invitation [get]
|
||||
func (c *ApiController) GetInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
invitation, err := object.GetInvitation(id)
|
||||
if err != nil {
|
||||
@@ -94,8 +94,8 @@ func (c *ApiController) GetInvitation() {
|
||||
// @Success 200 {object} object.Invitation The Response object
|
||||
// @router /get-invitation-info [get]
|
||||
func (c *ApiController) GetInvitationCodeInfo() {
|
||||
code := c.Input().Get("code")
|
||||
applicationId := c.Input().Get("applicationId")
|
||||
code := c.Ctx.Input.Query("code")
|
||||
applicationId := c.Ctx.Input.Query("applicationId")
|
||||
|
||||
application, err := object.GetApplication(applicationId)
|
||||
if err != nil {
|
||||
@@ -125,7 +125,7 @@ func (c *ApiController) GetInvitationCodeInfo() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-invitation [post]
|
||||
func (c *ApiController) UpdateInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var invitation object.Invitation
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
|
||||
@@ -184,7 +184,7 @@ func (c *ApiController) DeleteInvitation() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /verify-invitation [get]
|
||||
func (c *ApiController) VerifyInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
payment, attachInfo, err := object.VerifyInvitation(id)
|
||||
if err != nil {
|
||||
@@ -204,7 +204,7 @@ func (c *ApiController) VerifyInvitation() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /send-invitation [post]
|
||||
func (c *ApiController) SendInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var destinations []string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &destinations)
|
||||
@@ -234,10 +234,19 @@ func (c *ApiController) SendInvitation() {
|
||||
return
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByOrganizationName(invitation.Owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
var application *object.Application
|
||||
if invitation.Application != "" {
|
||||
application, err = object.GetApplication(fmt.Sprintf("admin/%s-org-%s", invitation.Application, invitation.Owner))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
application, err = object.GetApplicationByOrganizationName(invitation.Owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
@@ -245,6 +254,10 @@ func (c *ApiController) SendInvitation() {
|
||||
return
|
||||
}
|
||||
|
||||
if application.IsShared {
|
||||
application.Name = fmt.Sprintf("%s-org-%s", application.Name, invitation.Owner)
|
||||
}
|
||||
|
||||
provider, err := application.GetEmailProvider("Invitation")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -46,7 +46,7 @@ type LdapSyncResp struct {
|
||||
// @Success 200 {object} controllers.LdapResp The Response object
|
||||
// @router /get-ldap-users [get]
|
||||
func (c *ApiController) GetLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
_, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
@@ -114,7 +114,7 @@ func (c *ApiController) GetLdapUsers() {
|
||||
// @Success 200 {array} object.Ldap The Response object
|
||||
// @router /get-ldaps [get]
|
||||
func (c *ApiController) GetLdaps() {
|
||||
owner := c.Input().Get("owner")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
|
||||
c.ResponseOk(object.GetMaskedLdaps(object.GetLdaps(owner)))
|
||||
}
|
||||
@@ -127,7 +127,7 @@ func (c *ApiController) GetLdaps() {
|
||||
// @Success 200 {object} object.Ldap The Response object
|
||||
// @router /get-ldap [get]
|
||||
func (c *ApiController) GetLdap() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
if util.IsStringsEmpty(id) {
|
||||
c.ResponseError(c.T("general:Missing parameter"))
|
||||
@@ -266,7 +266,7 @@ func (c *ApiController) DeleteLdap() {
|
||||
// @Success 200 {object} controllers.LdapSyncResp The Response object
|
||||
// @router /sync-ldap-users [post]
|
||||
func (c *ApiController) SyncLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
owner, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
|
||||
@@ -64,7 +64,14 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
return
|
||||
}
|
||||
|
||||
mfaProps, err := MfaUtil.Initiate(user.GetId())
|
||||
issuer := ""
|
||||
if organization != nil && organization.DisplayName != "" {
|
||||
issuer = organization.DisplayName
|
||||
} else if organization != nil {
|
||||
issuer = organization.Name
|
||||
}
|
||||
|
||||
mfaProps, err := MfaUtil.Initiate(user.GetId(), issuer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Model The Response object
|
||||
// @router /get-models [get]
|
||||
func (c *ApiController) GetModels() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
models, err := object.GetModels(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetModels() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
models, err := object.GetPaginationModels(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetModels() {
|
||||
// @Success 200 {object} object.Model The Response object
|
||||
// @router /get-model [get]
|
||||
func (c *ApiController) GetModel() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
model, err := object.GetModel(id)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetModel() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-model [post]
|
||||
func (c *ApiController) UpdateModel() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var model object.Model
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
||||
|
||||
@@ -85,11 +85,12 @@ func (c *RootController) GetJwksByApplication() {
|
||||
// @Success 200 {object} object.WebFinger
|
||||
// @router /.well-known/webfinger [get]
|
||||
func (c *RootController) GetWebFinger() {
|
||||
resource := c.Input().Get("resource")
|
||||
resource := c.Ctx.Input.Query("resource")
|
||||
rels := []string{}
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
for key, value := range c.Input() {
|
||||
inputs, _ := c.Input()
|
||||
for key, value := range inputs {
|
||||
if strings.HasPrefix(key, "rel") {
|
||||
rels = append(rels, value...)
|
||||
}
|
||||
@@ -115,11 +116,12 @@ func (c *RootController) GetWebFinger() {
|
||||
// @router /.well-known/:application/webfinger [get]
|
||||
func (c *RootController) GetWebFingerByApplication() {
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
resource := c.Input().Get("resource")
|
||||
resource := c.Ctx.Input.Query("resource")
|
||||
rels := []string{}
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
for key, value := range c.Input() {
|
||||
inputs, _ := c.Input()
|
||||
for key, value := range inputs {
|
||||
if strings.HasPrefix(key, "rel") {
|
||||
rels = append(rels, value...)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Order The Response object
|
||||
// @router /get-orders [get]
|
||||
func (c *ApiController) GetOrders() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
orders, err := object.GetOrders(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetOrders() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
orders, err := object.GetPaginationOrders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -74,8 +74,8 @@ func (c *ApiController) GetOrders() {
|
||||
// @Success 200 {array} object.Order The Response object
|
||||
// @router /get-user-orders [get]
|
||||
func (c *ApiController) GetUserOrders() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
user := c.Ctx.Input.Query("user")
|
||||
|
||||
orders, err := object.GetUserOrders(owner, user)
|
||||
if err != nil {
|
||||
@@ -94,7 +94,7 @@ func (c *ApiController) GetUserOrders() {
|
||||
// @Success 200 {object} object.Order The Response object
|
||||
// @router /get-order [get]
|
||||
func (c *ApiController) GetOrder() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
order, err := object.GetOrder(id)
|
||||
if err != nil {
|
||||
@@ -114,7 +114,7 @@ func (c *ApiController) GetOrder() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-order [post]
|
||||
func (c *ApiController) UpdateOrder() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var order object.Order
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &order)
|
||||
|
||||
@@ -34,11 +34,11 @@ import (
|
||||
// @Success 200 {object} object.Order The Response object
|
||||
// @router /place-order [post]
|
||||
func (c *ApiController) PlaceOrder() {
|
||||
productId := c.Input().Get("productId")
|
||||
pricingName := c.Input().Get("pricingName")
|
||||
planName := c.Input().Get("planName")
|
||||
customPriceStr := c.Input().Get("customPrice")
|
||||
paidUserName := c.Input().Get("userName")
|
||||
productId := c.Ctx.Input.Query("productId")
|
||||
pricingName := c.Ctx.Input.Query("pricingName")
|
||||
planName := c.Ctx.Input.Query("planName")
|
||||
customPriceStr := c.Ctx.Input.Query("customPrice")
|
||||
paidUserName := c.Ctx.Input.Query("userName")
|
||||
|
||||
if productId == "" {
|
||||
c.ResponseError(c.T("general:ProductId is required"))
|
||||
@@ -107,10 +107,10 @@ func (c *ApiController) PlaceOrder() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /pay-order [post]
|
||||
func (c *ApiController) PayOrder() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
host := c.Ctx.Request.Host
|
||||
providerName := c.Input().Get("providerName")
|
||||
paymentEnv := c.Input().Get("paymentEnv")
|
||||
providerName := c.Ctx.Input.Query("providerName")
|
||||
paymentEnv := c.Ctx.Input.Query("paymentEnv")
|
||||
|
||||
order, err := object.GetOrder(id)
|
||||
if err != nil {
|
||||
@@ -129,7 +129,7 @@ func (c *ApiController) PayOrder() {
|
||||
return
|
||||
}
|
||||
|
||||
payment, attachInfo, err := object.PayOrder(providerName, host, paymentEnv, order)
|
||||
payment, attachInfo, err := object.PayOrder(providerName, host, paymentEnv, order, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -146,7 +146,7 @@ func (c *ApiController) PayOrder() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /cancel-order [post]
|
||||
func (c *ApiController) CancelOrder() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
order, err := object.GetOrder(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,14 +30,14 @@ import (
|
||||
// @Success 200 {array} object.Organization The Response object
|
||||
// @router /get-organizations [get]
|
||||
func (c *ApiController) GetOrganizations() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organizationName := c.Input().Get("organizationName")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organizationName := c.Ctx.Input.Query("organizationName")
|
||||
|
||||
isGlobalAdmin := c.IsGlobalAdmin()
|
||||
if limit == "" || page == "" {
|
||||
@@ -71,7 +71,7 @@ func (c *ApiController) GetOrganizations() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
organizations, err := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, organizationName, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -91,7 +91,7 @@ func (c *ApiController) GetOrganizations() {
|
||||
// @Success 200 {object} object.Organization The Response object
|
||||
// @router /get-organization [get]
|
||||
func (c *ApiController) GetOrganization() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
organization, err := object.GetMaskedOrganization(object.GetOrganization(id))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -114,7 +114,7 @@ func (c *ApiController) GetOrganization() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-organization [post]
|
||||
func (c *ApiController) UpdateOrganization() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var organization object.Organization
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
||||
@@ -205,7 +205,7 @@ func (c *ApiController) DeleteOrganization() {
|
||||
// @router /get-default-application [get]
|
||||
func (c *ApiController) GetDefaultApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
application, err := object.GetDefaultApplication(id)
|
||||
if err != nil {
|
||||
@@ -225,7 +225,7 @@ func (c *ApiController) GetDefaultApplication() {
|
||||
// @Success 200 {array} object.Organization The Response object
|
||||
// @router /get-organization-names [get]
|
||||
func (c *ApiController) GetOrganizationNames() {
|
||||
owner := c.Input().Get("owner")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
organizationNames, err := object.GetOrganizationsByFields(owner, []string{"name", "display_name"}...)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Payment The Response object
|
||||
// @router /get-payments [get]
|
||||
func (c *ApiController) GetPayments() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
payments, err := object.GetPayments(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetPayments() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
payments, err := object.GetPaginationPayments(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -75,8 +75,8 @@ func (c *ApiController) GetPayments() {
|
||||
// @Success 200 {array} object.Payment The Response object
|
||||
// @router /get-user-payments [get]
|
||||
func (c *ApiController) GetUserPayments() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
user := c.Ctx.Input.Query("user")
|
||||
|
||||
payments, err := object.GetUserPayments(owner, user)
|
||||
if err != nil {
|
||||
@@ -95,7 +95,7 @@ func (c *ApiController) GetUserPayments() {
|
||||
// @Success 200 {object} object.Payment The Response object
|
||||
// @router /get-payment [get]
|
||||
func (c *ApiController) GetPayment() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
payment, err := object.GetPayment(id)
|
||||
if err != nil {
|
||||
@@ -115,7 +115,7 @@ func (c *ApiController) GetPayment() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-payment [post]
|
||||
func (c *ApiController) UpdatePayment() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var payment object.Payment
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
||||
@@ -179,7 +179,7 @@ func (c *ApiController) NotifyPayment() {
|
||||
|
||||
body := c.Ctx.Input.RequestBody
|
||||
|
||||
payment, err := object.NotifyPayment(body, owner, paymentName)
|
||||
payment, err := object.NotifyPayment(body, owner, paymentName, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -196,7 +196,7 @@ func (c *ApiController) NotifyPayment() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /invoice-payment [post]
|
||||
func (c *ApiController) InvoicePayment() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
payment, err := object.GetPayment(id)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Permission The Response object
|
||||
// @router /get-permissions [get]
|
||||
func (c *ApiController) GetPermissions() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
permissions, err := object.GetPermissions(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetPermissions() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
permissions, err := object.GetPaginationPermissions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -94,7 +94,7 @@ func (c *ApiController) GetPermissionsBySubmitter() {
|
||||
// @Success 200 {array} object.Permission The Response object
|
||||
// @router /get-permissions-by-role [get]
|
||||
func (c *ApiController) GetPermissionsByRole() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
permissions, err := object.GetPermissionsByRole(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -112,7 +112,7 @@ func (c *ApiController) GetPermissionsByRole() {
|
||||
// @Success 200 {object} object.Permission The Response object
|
||||
// @router /get-permission [get]
|
||||
func (c *ApiController) GetPermission() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
permission, err := object.GetPermission(id)
|
||||
if err != nil {
|
||||
@@ -132,7 +132,7 @@ func (c *ApiController) GetPermission() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-permission [post]
|
||||
func (c *ApiController) UpdatePermission() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var permission object.Permission
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Plan The Response object
|
||||
// @router /get-plans [get]
|
||||
func (c *ApiController) GetPlans() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
plans, err := object.GetPlans(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetPlans() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
plan, err := object.GetPaginatedPlans(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -74,8 +74,8 @@ func (c *ApiController) GetPlans() {
|
||||
// @Success 200 {object} object.Plan The Response object
|
||||
// @router /get-plan [get]
|
||||
func (c *ApiController) GetPlan() {
|
||||
id := c.Input().Get("id")
|
||||
includeOption := c.Input().Get("includeOption") == "true"
|
||||
id := c.Ctx.Input.Query("id")
|
||||
includeOption := c.Ctx.Input.Query("includeOption") == "true"
|
||||
|
||||
plan, err := object.GetPlan(id)
|
||||
if err != nil {
|
||||
@@ -107,7 +107,7 @@ func (c *ApiController) GetPlan() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-plan [post]
|
||||
func (c *ApiController) UpdatePlan() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
owner := util.GetOwnerFromId(id)
|
||||
var plan object.Plan
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Pricing The Response object
|
||||
// @router /get-pricings [get]
|
||||
func (c *ApiController) GetPricings() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
pricings, err := object.GetPricings(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetPricings() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
pricing, err := object.GetPaginatedPricings(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetPricings() {
|
||||
// @Success 200 {object} object.Pricing The Response object
|
||||
// @router /get-pricing [get]
|
||||
func (c *ApiController) GetPricing() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
pricing, err := object.GetPricing(id)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetPricing() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-pricing [post]
|
||||
func (c *ApiController) UpdatePricing() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var pricing object.Pricing
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &pricing)
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Product The Response object
|
||||
// @router /get-products [get]
|
||||
func (c *ApiController) GetProducts() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
products, err := object.GetProducts(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetProducts() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
products, err := object.GetPaginationProducts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetProducts() {
|
||||
// @Success 200 {object} object.Product The Response object
|
||||
// @router /get-product [get]
|
||||
func (c *ApiController) GetProduct() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
product, err := object.GetProduct(id)
|
||||
if err != nil {
|
||||
@@ -99,7 +99,7 @@ func (c *ApiController) GetProduct() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-product [post]
|
||||
func (c *ApiController) UpdateProduct() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var product object.Product
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Provider The Response object
|
||||
// @router /get-providers [get]
|
||||
func (c *ApiController) GetProviders() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||
if !ok {
|
||||
@@ -59,7 +59,7 @@ func (c *ApiController) GetProviders() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
paginationProviders, err := object.GetPaginationProviders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -78,12 +78,12 @@ func (c *ApiController) GetProviders() {
|
||||
// @Success 200 {array} object.Provider The Response object
|
||||
// @router /get-global-providers [get]
|
||||
func (c *ApiController) GetGlobalProviders() {
|
||||
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")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||
if !ok {
|
||||
@@ -106,7 +106,7 @@ func (c *ApiController) GetGlobalProviders() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
paginationGlobalProviders, err := object.GetPaginationGlobalProviders(paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -126,7 +126,7 @@ func (c *ApiController) GetGlobalProviders() {
|
||||
// @Success 200 {object} object.Provider The Response object
|
||||
// @router /get-provider [get]
|
||||
func (c *ApiController) GetProvider() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||
if !ok {
|
||||
@@ -164,7 +164,7 @@ func (c *ApiController) requireProviderPermission(provider *object.Provider) boo
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-provider [post]
|
||||
func (c *ApiController) UpdateProvider() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var provider object.Provider
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -38,13 +38,13 @@ func (c *ApiController) GetRecords() {
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
organizationName := c.Input().Get("organizationName")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organizationName := c.Ctx.Input.Query("organizationName")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
records, err := object.GetRecords()
|
||||
@@ -66,7 +66,7 @@ func (c *ApiController) GetRecords() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
records, err := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -44,14 +44,14 @@ import (
|
||||
// @Success 200 {array} object.Resource The Response object
|
||||
// @router /get-resources [get]
|
||||
func (c *ApiController) GetResources() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
user := c.Ctx.Input.Query("user")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
isOrgAdmin, ok := c.IsOrgAdmin()
|
||||
if !ok {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetResources() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
resources, err := object.GetPaginationResources(owner, user, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -112,7 +112,7 @@ func (c *ApiController) GetResources() {
|
||||
// @Success 200 {object} object.Resource The Response object
|
||||
// @router /get-resource [get]
|
||||
func (c *ApiController) GetResource() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
resource, err := object.GetResource(id)
|
||||
if err != nil {
|
||||
@@ -132,7 +132,7 @@ func (c *ApiController) GetResource() {
|
||||
// @Success 200 {object} controllers.Response Success or error
|
||||
// @router /update-resource [post]
|
||||
func (c *ApiController) UpdateResource() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var resource object.Resource
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
||||
@@ -178,9 +178,11 @@ func (c *ApiController) DeleteResource() {
|
||||
}
|
||||
|
||||
if resource.Provider != "" {
|
||||
c.Input().Set("provider", resource.Provider)
|
||||
inputs, _ := c.Input()
|
||||
inputs.Set("provider", resource.Provider)
|
||||
}
|
||||
c.Input().Set("fullFilePath", resource.Name)
|
||||
inputs, _ := c.Input()
|
||||
inputs.Set("fullFilePath", resource.Name)
|
||||
provider, err := c.GetProviderFromContext("Storage")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -188,7 +190,7 @@ func (c *ApiController) DeleteResource() {
|
||||
}
|
||||
_, resource.Name = refineFullFilePath(resource.Name)
|
||||
|
||||
tag := c.Input().Get("tag")
|
||||
tag := c.Ctx.Input.Query("tag")
|
||||
if tag == "Direct" {
|
||||
resource.Name = path.Join(provider.PathPrefix, resource.Name)
|
||||
}
|
||||
@@ -218,14 +220,14 @@ func (c *ApiController) DeleteResource() {
|
||||
// @Success 200 {object} object.Resource FileUrl, objectKey
|
||||
// @router /upload-resource [post]
|
||||
func (c *ApiController) UploadResource() {
|
||||
owner := c.Input().Get("owner")
|
||||
username := c.Input().Get("user")
|
||||
application := c.Input().Get("application")
|
||||
tag := c.Input().Get("tag")
|
||||
parent := c.Input().Get("parent")
|
||||
fullFilePath := c.Input().Get("fullFilePath")
|
||||
createdTime := c.Input().Get("createdTime")
|
||||
description := c.Input().Get("description")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
username := c.Ctx.Input.Query("user")
|
||||
application := c.Ctx.Input.Query("application")
|
||||
tag := c.Ctx.Input.Query("tag")
|
||||
parent := c.Ctx.Input.Query("parent")
|
||||
fullFilePath := c.Ctx.Input.Query("fullFilePath")
|
||||
createdTime := c.Ctx.Input.Query("createdTime")
|
||||
description := c.Ctx.Input.Query("description")
|
||||
|
||||
file, header, err := c.GetFile("file")
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Role The Response object
|
||||
// @router /get-roles [get]
|
||||
func (c *ApiController) GetRoles() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
roles, err := object.GetRoles(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetRoles() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
roles, err := object.GetPaginationRoles(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetRoles() {
|
||||
// @Success 200 {object} object.Role The Response object
|
||||
// @router /get-role [get]
|
||||
func (c *ApiController) GetRole() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
role, err := object.GetRole(id)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetRole() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-role [post]
|
||||
func (c *ApiController) UpdateRole() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var role object.Role
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
func (c *ApiController) GetSamlMeta() {
|
||||
host := c.Ctx.Request.Host
|
||||
paramApp := c.Input().Get("application")
|
||||
paramApp := c.Ctx.Input.Query("application")
|
||||
application, err := object.GetApplication(paramApp)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -57,10 +57,10 @@ func (c *ApiController) HandleSamlRedirect() {
|
||||
owner := c.Ctx.Input.Param(":owner")
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
|
||||
relayState := c.Input().Get("RelayState")
|
||||
samlRequest := c.Input().Get("SAMLRequest")
|
||||
username := c.Input().Get("username")
|
||||
loginHint := c.Input().Get("login_hint")
|
||||
relayState := c.Ctx.Input.Query("RelayState")
|
||||
samlRequest := c.Ctx.Input.Query("SAMLRequest")
|
||||
username := c.Ctx.Input.Query("username")
|
||||
loginHint := c.Ctx.Input.Query("login_hint")
|
||||
|
||||
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host, username, loginHint)
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +32,13 @@ import (
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /get-sessions [get]
|
||||
func (c *ApiController) GetSessions() {
|
||||
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")
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
sessions, err := object.GetSessions(owner)
|
||||
@@ -53,7 +55,7 @@ func (c *ApiController) GetSessions() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
sessions, err := object.GetPaginationSessions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -68,11 +70,11 @@ func (c *ApiController) GetSessions() {
|
||||
// @Title GetSingleSession
|
||||
// @Tag Session API
|
||||
// @Description Get session for one user in one application.
|
||||
// @Param sessionPkId query string true "The id(organization/user/application) of session"
|
||||
// @Param sessionPkId query string true "The session ID in format: organization/user/application (e.g., built-in/admin/app-built-in)"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /get-session [get]
|
||||
func (c *ApiController) GetSingleSession() {
|
||||
id := c.Input().Get("sessionPkId")
|
||||
id := c.Ctx.Input.Query("sessionPkId")
|
||||
|
||||
session, err := object.GetSingleSession(id)
|
||||
if err != nil {
|
||||
@@ -87,8 +89,8 @@ func (c *ApiController) GetSingleSession() {
|
||||
// @Title UpdateSession
|
||||
// @Tag Session API
|
||||
// @Description Update session for one user in one application.
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @Param body body object.Session true "The session object to update"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-session [post]
|
||||
func (c *ApiController) UpdateSession() {
|
||||
var session object.Session
|
||||
@@ -106,9 +108,8 @@ func (c *ApiController) UpdateSession() {
|
||||
// @Title AddSession
|
||||
// @Tag Session API
|
||||
// @Description Add session for one user in one application. If there are other existing sessions, join the session into the list.
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Param sessionId query string true "sessionId to be added"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @Param body body object.Session true "The session object to add"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-session [post]
|
||||
func (c *ApiController) AddSession() {
|
||||
var session object.Session
|
||||
@@ -126,8 +127,8 @@ func (c *ApiController) AddSession() {
|
||||
// @Title DeleteSession
|
||||
// @Tag Session API
|
||||
// @Description Delete session for one user in one application.
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @Param body body object.Session true "The session object to delete"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-session [post]
|
||||
func (c *ApiController) DeleteSession() {
|
||||
var session object.Session
|
||||
@@ -137,7 +138,21 @@ func (c *ApiController) DeleteSession() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application)))
|
||||
curSessionId := c.Ctx.Input.CruSession.SessionID(context.Background())
|
||||
|
||||
sessionId := c.Ctx.Input.Query("sessionId")
|
||||
if curSessionId == sessionId && sessionId != "" {
|
||||
c.ResponseError(fmt.Sprintf(c.T("session:session id %s is the current session and cannot be deleted"), curSessionId))
|
||||
return
|
||||
}
|
||||
|
||||
if sessionId != "" {
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteSessionId(util.GetSessionId(session.Owner, session.Name, session.Application), sessionId))
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application), curSessionId))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -145,13 +160,13 @@ func (c *ApiController) DeleteSession() {
|
||||
// @Title IsSessionDuplicated
|
||||
// @Tag Session API
|
||||
// @Description Check if there are other different sessions for one user in one application.
|
||||
// @Param sessionPkId query string true "The id(organization/user/application) of session"
|
||||
// @Param sessionId query string true "sessionId to be checked"
|
||||
// @Param sessionPkId query string true "The session ID in format: organization/user/application (e.g., built-in/admin/app-built-in)"
|
||||
// @Param sessionId query string true "The specific session ID to check"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /is-session-duplicated [get]
|
||||
func (c *ApiController) IsSessionDuplicated() {
|
||||
id := c.Input().Get("sessionPkId")
|
||||
sessionId := c.Input().Get("sessionId")
|
||||
id := c.Ctx.Input.Query("sessionPkId")
|
||||
sessionId := c.Ctx.Input.Query("sessionId")
|
||||
|
||||
isUserSessionDuplicated, err := object.IsSessionDuplicated(id, sessionId)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Subscription The Response object
|
||||
// @router /get-subscriptions [get]
|
||||
func (c *ApiController) GetSubscriptions() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
subscriptions, err := object.GetSubscriptions(owner)
|
||||
@@ -54,7 +54,7 @@ func (c *ApiController) GetSubscriptions() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
subscription, err := object.GetPaginationSubscriptions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,7 +73,7 @@ func (c *ApiController) GetSubscriptions() {
|
||||
// @Success 200 {object} object.Subscription The Response object
|
||||
// @router /get-subscription [get]
|
||||
func (c *ApiController) GetSubscription() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
subscription, err := object.GetSubscription(id)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func (c *ApiController) GetSubscription() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-subscription [post]
|
||||
func (c *ApiController) UpdateSubscription() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var subscription object.Subscription
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &subscription)
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -31,14 +31,14 @@ import (
|
||||
// @Success 200 {array} object.Syncer The Response object
|
||||
// @router /get-syncers [get]
|
||||
func (c *ApiController) GetSyncers() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organization := c.Input().Get("organization")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
syncers, err := object.GetMaskedSyncers(object.GetOrganizationSyncers(owner, organization))
|
||||
@@ -56,7 +56,7 @@ func (c *ApiController) GetSyncers() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
syncers, err := object.GetMaskedSyncers(object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -75,7 +75,7 @@ func (c *ApiController) GetSyncers() {
|
||||
// @Success 200 {object} object.Syncer The Response object
|
||||
// @router /get-syncer [get]
|
||||
func (c *ApiController) GetSyncer() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
syncer, err := object.GetMaskedSyncer(object.GetSyncer(id))
|
||||
if err != nil {
|
||||
@@ -95,7 +95,7 @@ func (c *ApiController) GetSyncer() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-syncer [post]
|
||||
func (c *ApiController) UpdateSyncer() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var syncer object.Syncer
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||
@@ -154,7 +154,7 @@ func (c *ApiController) DeleteSyncer() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /run-syncer [get]
|
||||
func (c *ApiController) RunSyncer() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
syncer, err := object.GetSyncer(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
271
controllers/ticket.go
Normal file
271
controllers/ticket.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// Copyright 2024 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/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetTickets
|
||||
// @Title GetTickets
|
||||
// @Tag Ticket API
|
||||
// @Description get tickets
|
||||
// @Param owner query string true "The owner of tickets"
|
||||
// @Success 200 {array} object.Ticket The Response object
|
||||
// @router /get-tickets [get]
|
||||
func (c *ApiController) GetTickets() {
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
user := c.getCurrentUser()
|
||||
isAdmin := c.IsAdmin()
|
||||
|
||||
var tickets []*object.Ticket
|
||||
var err error
|
||||
|
||||
if limit == "" || page == "" {
|
||||
if isAdmin {
|
||||
tickets, err = object.GetTickets(owner)
|
||||
} else {
|
||||
tickets, err = object.GetUserTickets(owner, user.GetId())
|
||||
}
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(tickets)
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
var count int64
|
||||
|
||||
if isAdmin {
|
||||
count, err = object.GetTicketCount(owner, field, value)
|
||||
} else {
|
||||
// For non-admin users, only show their own tickets
|
||||
tickets, err = object.GetUserTickets(owner, user.GetId())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
count = int64(len(tickets))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
|
||||
if isAdmin {
|
||||
tickets, err = object.GetPaginationTickets(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(tickets, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// GetTicket
|
||||
// @Title GetTicket
|
||||
// @Tag Ticket API
|
||||
// @Description get ticket
|
||||
// @Param id query string true "The id ( owner/name ) of the ticket"
|
||||
// @Success 200 {object} object.Ticket The Response object
|
||||
// @router /get-ticket [get]
|
||||
func (c *ApiController) GetTicket() {
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
ticket, err := object.GetTicket(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Check permission: user can only view their own tickets unless they are admin
|
||||
user := c.getCurrentUser()
|
||||
isAdmin := c.IsAdmin()
|
||||
|
||||
if ticket != nil && !isAdmin && ticket.User != user.GetId() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(ticket)
|
||||
}
|
||||
|
||||
// UpdateTicket
|
||||
// @Title UpdateTicket
|
||||
// @Tag Ticket API
|
||||
// @Description update ticket
|
||||
// @Param id query string true "The id ( owner/name ) of the ticket"
|
||||
// @Param body body object.Ticket true "The details of the ticket"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-ticket [post]
|
||||
func (c *ApiController) UpdateTicket() {
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var ticket object.Ticket
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Check permission
|
||||
user := c.getCurrentUser()
|
||||
isAdmin := c.IsAdmin()
|
||||
|
||||
existingTicket, err := object.GetTicket(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if existingTicket == nil {
|
||||
c.ResponseError(c.T("ticket:Ticket not found"))
|
||||
return
|
||||
}
|
||||
|
||||
// Normal users can only close their own tickets
|
||||
if !isAdmin {
|
||||
if existingTicket.User != user.GetId() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
// Normal users can only change state to "Closed"
|
||||
if ticket.State != "Closed" && ticket.State != existingTicket.State {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
// Preserve original fields that users shouldn't modify
|
||||
ticket.Owner = existingTicket.Owner
|
||||
ticket.Name = existingTicket.Name
|
||||
ticket.User = existingTicket.User
|
||||
ticket.CreatedTime = existingTicket.CreatedTime
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateTicket(id, &ticket))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// AddTicket
|
||||
// @Title AddTicket
|
||||
// @Tag Ticket API
|
||||
// @Description add ticket
|
||||
// @Param body body object.Ticket true "The details of the ticket"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-ticket [post]
|
||||
func (c *ApiController) AddTicket() {
|
||||
var ticket object.Ticket
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Set the user field to the current user
|
||||
user := c.getCurrentUser()
|
||||
ticket.User = user.GetId()
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddTicket(&ticket))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// DeleteTicket
|
||||
// @Title DeleteTicket
|
||||
// @Tag Ticket API
|
||||
// @Description delete ticket
|
||||
// @Param body body object.Ticket true "The details of the ticket"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-ticket [post]
|
||||
func (c *ApiController) DeleteTicket() {
|
||||
var ticket object.Ticket
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Only admins can delete tickets
|
||||
if !c.IsAdmin() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteTicket(&ticket))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// AddTicketMessage
|
||||
// @Title AddTicketMessage
|
||||
// @Tag Ticket API
|
||||
// @Description add a message to a ticket
|
||||
// @Param id query string true "The id ( owner/name ) of the ticket"
|
||||
// @Param body body object.TicketMessage true "The message to add"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-ticket-message [post]
|
||||
func (c *ApiController) AddTicketMessage() {
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var message object.TicketMessage
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Check permission
|
||||
user := c.getCurrentUser()
|
||||
isAdmin := c.IsAdmin()
|
||||
|
||||
ticket, err := object.GetTicket(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if ticket == nil {
|
||||
c.ResponseError(c.T("ticket:Ticket not found"))
|
||||
return
|
||||
}
|
||||
|
||||
// Users can only add messages to their own tickets, admins can add to any ticket
|
||||
if !isAdmin && ticket.User != user.GetId() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
// Set the author and admin flag
|
||||
message.Author = user.GetId()
|
||||
message.IsAdmin = isAdmin
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddTicketMessage(id, &message))
|
||||
c.ServeJSON()
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -28,20 +28,20 @@ import (
|
||||
// @Title GetTokens
|
||||
// @Tag Token API
|
||||
// @Description get tokens
|
||||
// @Param owner query string true "The owner of tokens"
|
||||
// @Param owner query string true "The organization name (e.g., built-in)"
|
||||
// @Param pageSize query string true "The size of each page"
|
||||
// @Param p query string true "The number of the page"
|
||||
// @Success 200 {array} object.Token The Response object
|
||||
// @router /get-tokens [get]
|
||||
func (c *ApiController) GetTokens() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organization := c.Input().Get("organization")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
if limit == "" || page == "" {
|
||||
token, err := object.GetTokens(owner, organization)
|
||||
if err != nil {
|
||||
@@ -58,7 +58,7 @@ func (c *ApiController) GetTokens() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
tokens, err := object.GetPaginationTokens(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -73,11 +73,11 @@ func (c *ApiController) GetTokens() {
|
||||
// @Title GetToken
|
||||
// @Tag Token API
|
||||
// @Description get token
|
||||
// @Param id query string true "The id ( owner/name ) of token"
|
||||
// @Param id query string true "The token ID in format: organization/token-name (e.g., built-in/token-123456)"
|
||||
// @Success 200 {object} object.Token The Response object
|
||||
// @router /get-token [get]
|
||||
func (c *ApiController) GetToken() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
token, err := object.GetToken(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -91,12 +91,12 @@ func (c *ApiController) GetToken() {
|
||||
// @Title UpdateToken
|
||||
// @Tag Token API
|
||||
// @Description update token
|
||||
// @Param id query string true "The id ( owner/name ) of token"
|
||||
// @Param id query string true "The token ID in format: organization/token-name (e.g., built-in/token-123456)"
|
||||
// @Param body body object.Token true "Details of the token"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-token [post]
|
||||
func (c *ApiController) UpdateToken() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var token object.Token
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
||||
@@ -160,19 +160,19 @@ func (c *ApiController) DeleteToken() {
|
||||
// @Success 401 {object} object.TokenError The Response object
|
||||
// @router /login/oauth/access_token [post]
|
||||
func (c *ApiController) GetOAuthToken() {
|
||||
clientId := c.Input().Get("client_id")
|
||||
clientSecret := c.Input().Get("client_secret")
|
||||
grantType := c.Input().Get("grant_type")
|
||||
code := c.Input().Get("code")
|
||||
verifier := c.Input().Get("code_verifier")
|
||||
scope := c.Input().Get("scope")
|
||||
nonce := c.Input().Get("nonce")
|
||||
username := c.Input().Get("username")
|
||||
password := c.Input().Get("password")
|
||||
tag := c.Input().Get("tag")
|
||||
avatar := c.Input().Get("avatar")
|
||||
refreshToken := c.Input().Get("refresh_token")
|
||||
deviceCode := c.Input().Get("device_code")
|
||||
clientId := c.Ctx.Input.Query("client_id")
|
||||
clientSecret := c.Ctx.Input.Query("client_secret")
|
||||
grantType := c.Ctx.Input.Query("grant_type")
|
||||
code := c.Ctx.Input.Query("code")
|
||||
verifier := c.Ctx.Input.Query("code_verifier")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
nonce := c.Ctx.Input.Query("nonce")
|
||||
username := c.Ctx.Input.Query("username")
|
||||
password := c.Ctx.Input.Query("password")
|
||||
tag := c.Ctx.Input.Query("tag")
|
||||
avatar := c.Ctx.Input.Query("avatar")
|
||||
refreshToken := c.Ctx.Input.Query("refresh_token")
|
||||
deviceCode := c.Ctx.Input.Query("device_code")
|
||||
|
||||
if clientId == "" && clientSecret == "" {
|
||||
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
|
||||
@@ -288,11 +288,11 @@ func (c *ApiController) GetOAuthToken() {
|
||||
// @Success 401 {object} object.TokenError The Response object
|
||||
// @router /login/oauth/refresh_token [post]
|
||||
func (c *ApiController) RefreshToken() {
|
||||
grantType := c.Input().Get("grant_type")
|
||||
refreshToken := c.Input().Get("refresh_token")
|
||||
scope := c.Input().Get("scope")
|
||||
clientId := c.Input().Get("client_id")
|
||||
clientSecret := c.Input().Get("client_secret")
|
||||
grantType := c.Ctx.Input.Query("grant_type")
|
||||
refreshToken := c.Ctx.Input.Query("refresh_token")
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
clientId := c.Ctx.Input.Query("client_id")
|
||||
clientSecret := c.Ctx.Input.Query("client_secret")
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
if clientId == "" {
|
||||
@@ -342,11 +342,11 @@ func (c *ApiController) ResponseTokenError(errorMsg string) {
|
||||
// @Success 401 {object} object.TokenError The Response object
|
||||
// @router /login/oauth/introspect [post]
|
||||
func (c *ApiController) IntrospectToken() {
|
||||
tokenValue := c.Input().Get("token")
|
||||
tokenValue := c.Ctx.Input.Query("token")
|
||||
clientId, clientSecret, ok := c.Ctx.Request.BasicAuth()
|
||||
if !ok {
|
||||
clientId = c.Input().Get("client_id")
|
||||
clientSecret = c.Input().Get("client_secret")
|
||||
clientId = c.Ctx.Input.Query("client_id")
|
||||
clientSecret = c.Ctx.Input.Query("client_secret")
|
||||
if clientId == "" || clientSecret == "" {
|
||||
c.ResponseTokenError(object.InvalidRequest)
|
||||
return
|
||||
@@ -369,7 +369,7 @@ func (c *ApiController) IntrospectToken() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
tokenTypeHint := c.Input().Get("token_type_hint")
|
||||
tokenTypeHint := c.Ctx.Input.Query("token_type_hint")
|
||||
var token *object.Token
|
||||
if tokenTypeHint != "" {
|
||||
token, err = object.GetTokenByTokenValue(tokenValue, tokenTypeHint)
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
// @Success 200 {array} object.Transaction The Response object
|
||||
// @router /get-transactions [get]
|
||||
func (c *ApiController) GetTransactions() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
var transactions []*object.Transaction
|
||||
@@ -86,7 +86,7 @@ func (c *ApiController) GetTransactions() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
transactions, err := object.GetPaginationTransactions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -105,7 +105,7 @@ func (c *ApiController) GetTransactions() {
|
||||
// @Success 200 {object} object.Transaction The Response object
|
||||
// @router /get-transaction [get]
|
||||
func (c *ApiController) GetTransaction() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
transaction, err := object.GetTransaction(id)
|
||||
if err != nil {
|
||||
@@ -146,7 +146,7 @@ func (c *ApiController) GetTransaction() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-transaction [post]
|
||||
func (c *ApiController) UpdateTransaction() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var transaction object.Transaction
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
|
||||
@@ -175,7 +175,7 @@ func (c *ApiController) AddTransaction() {
|
||||
return
|
||||
}
|
||||
|
||||
dryRunParam := c.Input().Get("dryRun")
|
||||
dryRunParam := c.Ctx.Input.Query("dryRun")
|
||||
dryRun := dryRunParam != ""
|
||||
|
||||
affected, transactionId, err := object.AddTransaction(&transaction, c.GetAcceptLanguage(), dryRun)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@@ -32,12 +32,12 @@ import (
|
||||
// @Success 200 {array} object.User The Response object
|
||||
// @router /get-global-users [get]
|
||||
func (c *ApiController) GetGlobalUsers() {
|
||||
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")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
users, err := object.GetMaskedUsers(object.GetGlobalUsers())
|
||||
@@ -55,7 +55,7 @@ func (c *ApiController) GetGlobalUsers() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
users, err := object.GetPaginationGlobalUsers(paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -80,14 +80,14 @@ func (c *ApiController) GetGlobalUsers() {
|
||||
// @Success 200 {array} object.User The Response object
|
||||
// @router /get-users [get]
|
||||
func (c *ApiController) GetUsers() {
|
||||
owner := c.Input().Get("owner")
|
||||
groupName := c.Input().Get("groupName")
|
||||
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")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
groupName := c.Ctx.Input.Query("groupName")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
if groupName != "" {
|
||||
@@ -115,7 +115,7 @@ func (c *ApiController) GetUsers() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
users, err := object.GetPaginationUsers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder, groupName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -144,11 +144,11 @@ func (c *ApiController) GetUsers() {
|
||||
// @Success 200 {object} object.User The Response object
|
||||
// @router /get-user [get]
|
||||
func (c *ApiController) GetUser() {
|
||||
id := c.Input().Get("id")
|
||||
email := c.Input().Get("email")
|
||||
phone := c.Input().Get("phone")
|
||||
userId := c.Input().Get("userId")
|
||||
owner := c.Input().Get("owner")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
email := c.Ctx.Input.Query("email")
|
||||
phone := c.Ctx.Input.Query("phone")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
var err error
|
||||
var userFromUserId *object.User
|
||||
if userId != "" && owner != "" {
|
||||
@@ -259,10 +259,10 @@ func (c *ApiController) GetUser() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-user [post]
|
||||
func (c *ApiController) UpdateUser() {
|
||||
id := c.Input().Get("id")
|
||||
userId := c.Input().Get("userId")
|
||||
owner := c.Input().Get("owner")
|
||||
columnsStr := c.Input().Get("columns")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
userId := c.Ctx.Input.Query("userId")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
columnsStr := c.Ctx.Input.Query("columns")
|
||||
|
||||
var user object.User
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||
@@ -336,7 +336,7 @@ func (c *ApiController) UpdateUser() {
|
||||
}
|
||||
|
||||
isAdmin := c.IsAdmin()
|
||||
allowDisplayNameEmpty := c.Input().Get("allowEmpty") != ""
|
||||
allowDisplayNameEmpty := c.Ctx.Input.Query("allowEmpty") != ""
|
||||
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, allowDisplayNameEmpty, c.GetAcceptLanguage()); !pass {
|
||||
c.ResponseError(err)
|
||||
return
|
||||
@@ -690,9 +690,9 @@ func (c *ApiController) CheckUserPassword() {
|
||||
// @Success 200 {array} object.User The Response object
|
||||
// @router /get-sorted-users [get]
|
||||
func (c *ApiController) GetSortedUsers() {
|
||||
owner := c.Input().Get("owner")
|
||||
sorter := c.Input().Get("sorter")
|
||||
limit := util.ParseInt(c.Input().Get("limit"))
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
sorter := c.Ctx.Input.Query("sorter")
|
||||
limit := util.ParseInt(c.Ctx.Input.Query("limit"))
|
||||
|
||||
users, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
|
||||
if err != nil {
|
||||
@@ -712,8 +712,8 @@ func (c *ApiController) GetSortedUsers() {
|
||||
// @Success 200 {int} int The count of filtered users for an organization
|
||||
// @router /get-user-count [get]
|
||||
func (c *ApiController) GetUserCount() {
|
||||
owner := c.Input().Get("owner")
|
||||
isOnline := c.Input().Get("isOnline")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
isOnline := c.Ctx.Input.Query("isOnline")
|
||||
|
||||
var count int64
|
||||
var err error
|
||||
@@ -777,3 +777,133 @@ func (c *ApiController) RemoveUserFromGroup() {
|
||||
|
||||
c.ResponseOk(affected)
|
||||
}
|
||||
|
||||
// VerifyIdentification
|
||||
// @Title VerifyIdentification
|
||||
// @Tag User API
|
||||
// @Description verify user's real identity using ID Verification provider
|
||||
// @Param owner query string false "The owner of the user (optional, defaults to logged-in user)"
|
||||
// @Param name query string false "The name of the user (optional, defaults to logged-in user)"
|
||||
// @Param provider query string false "The name of the ID Verification provider (optional, auto-selected if not provided)"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /verify-identification [post]
|
||||
func (c *ApiController) VerifyIdentification() {
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
name := c.Ctx.Input.Query("name")
|
||||
providerName := c.Ctx.Input.Query("provider")
|
||||
|
||||
// If user not specified, use logged-in user
|
||||
if owner == "" || name == "" {
|
||||
loggedInUser := c.GetSessionUsername()
|
||||
if loggedInUser == "" {
|
||||
c.ResponseError(c.T("general:Please login first"))
|
||||
return
|
||||
}
|
||||
var err error
|
||||
owner, name, err = util.GetOwnerAndNameFromIdWithError(loggedInUser)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If user is specified, check if current user has permission to verify other users
|
||||
// Only admins can verify other users
|
||||
loggedInUser := c.GetSessionUsername()
|
||||
if loggedInUser != util.GetId(owner, name) && !c.IsAdmin() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user, err := object.GetUser(util.GetId(owner, name))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(owner, name)))
|
||||
return
|
||||
}
|
||||
|
||||
if user.IdCard == "" || user.IdCardType == "" || user.RealName == "" {
|
||||
c.ResponseError(c.T("user:ID card information and real name are required"))
|
||||
return
|
||||
}
|
||||
|
||||
if user.IsVerified {
|
||||
c.ResponseError(c.T("user:User is already verified"))
|
||||
return
|
||||
}
|
||||
|
||||
var provider *object.Provider
|
||||
// If provider not specified, find suitable IDV provider from user's application
|
||||
if providerName == "" {
|
||||
application, err := object.GetApplicationByUser(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
c.ResponseError(c.T("user:No application found for user"))
|
||||
return
|
||||
}
|
||||
|
||||
// Find IDV provider from application
|
||||
idvProvider, err := object.GetIdvProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if idvProvider == nil {
|
||||
c.ResponseError(c.T("provider:No ID Verification provider configured"))
|
||||
return
|
||||
}
|
||||
provider = idvProvider
|
||||
} else {
|
||||
provider, err = object.GetProvider(providerName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("provider:The provider: %s does not exist"), providerName))
|
||||
return
|
||||
}
|
||||
|
||||
if provider.Category != "ID Verification" {
|
||||
c.ResponseError(c.T("provider:Provider is not an ID Verification provider"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
idvProvider := object.GetIdvProviderFromProvider(provider)
|
||||
if idvProvider == nil {
|
||||
c.ResponseError(c.T("provider:Failed to initialize ID Verification provider"))
|
||||
return
|
||||
}
|
||||
|
||||
verified, err := idvProvider.VerifyIdentity(user.IdCardType, user.IdCard, user.RealName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if !verified {
|
||||
c.ResponseError(c.T("user:Identity verification failed"))
|
||||
return
|
||||
}
|
||||
|
||||
// Set IsVerified to true upon successful verification
|
||||
user.IsVerified = true
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"is_verified"}, false)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(user.RealName)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
|
||||
}
|
||||
|
||||
if object.IsAppUser(userId) {
|
||||
tmpUserId := c.Input().Get("userId")
|
||||
tmpUserId := c.Ctx.Input.Query("userId")
|
||||
if tmpUserId != "" {
|
||||
userId = tmpUserId
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func (c *ApiController) IsOrgAdmin() (bool, bool) {
|
||||
// IsMaskedEnabled ...
|
||||
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
|
||||
isMaskEnabled := true
|
||||
withSecret := c.Input().Get("withSecret")
|
||||
withSecret := c.Ctx.Input.Query("withSecret")
|
||||
if withSecret == "1" {
|
||||
isMaskEnabled = false
|
||||
|
||||
@@ -202,14 +202,14 @@ func refineFullFilePath(fullFilePath string) (string, string) {
|
||||
}
|
||||
|
||||
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, error) {
|
||||
providerName := c.Input().Get("provider")
|
||||
providerName := c.Ctx.Input.Query("provider")
|
||||
if providerName == "" {
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
if field == "provider" && value != "" {
|
||||
providerName = value
|
||||
} else {
|
||||
fullFilePath := c.Input().Get("fullFilePath")
|
||||
fullFilePath := c.Ctx.Input.Query("fullFilePath")
|
||||
providerName, _ = refineFullFilePath(fullFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/captcha"
|
||||
"github.com/casdoor/casdoor/form"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@@ -49,14 +49,14 @@ func (c *ApiController) GetVerifications() {
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
|
||||
owner := c.Input().Get("owner")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
// For global admin with organizationName parameter, use it to filter
|
||||
// For org admin, use their organization
|
||||
if c.IsGlobalAdmin() && owner != "" {
|
||||
@@ -79,7 +79,7 @@ func (c *ApiController) GetVerifications() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
payments, err := object.GetPaginationVerifications(organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -100,8 +100,8 @@ func (c *ApiController) GetVerifications() {
|
||||
// @Success 200 {array} object.Verification The Response object
|
||||
// @router /get-user-payments [get]
|
||||
func (c *ApiController) GetUserVerifications() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
user := c.Ctx.Input.Query("user")
|
||||
|
||||
payments, err := object.GetUserVerifications(owner, user)
|
||||
if err != nil {
|
||||
@@ -120,7 +120,7 @@ func (c *ApiController) GetUserVerifications() {
|
||||
// @Success 200 {object} object.Verification The Response object
|
||||
// @router /get-payment [get]
|
||||
func (c *ApiController) GetVerification() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
payment, err := object.GetVerification(id)
|
||||
if err != nil {
|
||||
|
||||
@@ -126,8 +126,8 @@ func (c *ApiController) WebAuthnSigninBegin() {
|
||||
return
|
||||
}
|
||||
|
||||
userOwner := c.Input().Get("owner")
|
||||
userName := c.Input().Get("name")
|
||||
userOwner := c.Ctx.Input.Query("owner")
|
||||
userName := c.Ctx.Input.Query("name")
|
||||
|
||||
var options *protocol.CredentialAssertion
|
||||
var sessionData *webauthn.SessionData
|
||||
@@ -171,8 +171,8 @@ func (c *ApiController) WebAuthnSigninBegin() {
|
||||
// @Success 200 {object} controllers.Response "The Response object"
|
||||
// @router /webauthn/signin/finish [post]
|
||||
func (c *ApiController) WebAuthnSigninFinish() {
|
||||
responseType := c.Input().Get("responseType")
|
||||
clientId := c.Input().Get("clientId")
|
||||
responseType := c.Ctx.Input.Query("responseType")
|
||||
clientId := c.Ctx.Input.Query("clientId")
|
||||
webauthnObj, err := object.GetWebAuthnObject(c.Ctx.Request.Host)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -17,7 +17,7 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/beego/beego/v2/core/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
@@ -31,14 +31,14 @@ import (
|
||||
// @router /get-webhooks [get]
|
||||
// @Security test_apiKey
|
||||
func (c *ApiController) GetWebhooks() {
|
||||
owner := c.Input().Get("owner")
|
||||
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")
|
||||
organization := c.Input().Get("organization")
|
||||
owner := c.Ctx.Input.Query("owner")
|
||||
limit := c.Ctx.Input.Query("pageSize")
|
||||
page := c.Ctx.Input.Query("p")
|
||||
field := c.Ctx.Input.Query("field")
|
||||
value := c.Ctx.Input.Query("value")
|
||||
sortField := c.Ctx.Input.Query("sortField")
|
||||
sortOrder := c.Ctx.Input.Query("sortOrder")
|
||||
organization := c.Ctx.Input.Query("organization")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
webhooks, err := object.GetWebhooks(owner, organization)
|
||||
@@ -56,7 +56,7 @@ func (c *ApiController) GetWebhooks() {
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
|
||||
|
||||
webhooks, err := object.GetPaginationWebhooks(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
@@ -76,7 +76,7 @@ func (c *ApiController) GetWebhooks() {
|
||||
// @Success 200 {object} object.Webhook The Response object
|
||||
// @router /get-webhook [get]
|
||||
func (c *ApiController) GetWebhook() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
webhook, err := object.GetWebhook(id)
|
||||
if err != nil {
|
||||
@@ -96,7 +96,7 @@ func (c *ApiController) GetWebhook() {
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-webhook [post]
|
||||
func (c *ApiController) UpdateWebhook() {
|
||||
id := c.Input().Get("id")
|
||||
id := c.Ctx.Input.Query("id")
|
||||
|
||||
var webhook object.Webhook
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
||||
|
||||
184
go.mod
184
go.mod
@@ -6,20 +6,22 @@ require (
|
||||
github.com/Masterminds/squirrel v1.5.3
|
||||
github.com/NdoleStudio/lemonsqueezy-go v1.2.4
|
||||
github.com/PaddleHQ/paddle-go-sdk v1.0.0
|
||||
github.com/adyen/adyen-go-api-library/v11 v11.0.0
|
||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
||||
github.com/alibabacloud-go/cloudauth-20190307/v3 v3.9.2
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4
|
||||
github.com/alibabacloud-go/facebody-20191230/v5 v5.1.2
|
||||
github.com/alibabacloud-go/openapi-util v0.1.0
|
||||
github.com/alibabacloud-go/tea v1.3.2
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
|
||||
github.com/aws/aws-sdk-go v1.45.5
|
||||
github.com/beego/beego v1.12.12
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0
|
||||
github.com/beego/beego/v2 v2.3.8
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/casbin/casbin/v2 v2.77.2
|
||||
github.com/casdoor/go-sms-sender v0.25.0
|
||||
github.com/casdoor/gomail/v2 v2.2.0
|
||||
github.com/casdoor/ldapserver v1.2.0
|
||||
github.com/casdoor/notify v1.0.1
|
||||
github.com/casdoor/notify2 v1.6.0
|
||||
github.com/casdoor/oss v1.8.0
|
||||
github.com/casdoor/xorm-adapter/v3 v3.1.0
|
||||
github.com/casvisor/casvisor-go-sdk v1.4.0
|
||||
@@ -28,12 +30,13 @@ require (
|
||||
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5
|
||||
github.com/go-git/go-git/v5 v5.13.0
|
||||
github.com/go-git/go-git/v5 v5.16.3
|
||||
github.com/go-jose/go-jose/v4 v4.1.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-mysql-org/go-mysql v1.7.0
|
||||
github.com/go-pay/gopay v1.5.115
|
||||
github.com/go-pay/util v0.0.4
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||
github.com/go-webauthn/webauthn v0.10.2
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
@@ -42,19 +45,19 @@ require (
|
||||
github.com/lestrrat-go/jwx v1.2.29
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||
github.com/markbates/goth v1.79.0
|
||||
github.com/markbates/goth v1.82.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nyaruka/phonenumbers v1.2.2
|
||||
github.com/polarsource/polar-go v0.12.0
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/prometheus/client_model v0.6.0
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russellhaering/gosaml2 v0.9.0
|
||||
github.com/russellhaering/goxmldsig v1.2.0
|
||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/sendgrid/sendgrid-go v3.16.0+incompatible
|
||||
github.com/shirou/gopsutil/v4 v4.25.9
|
||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stripe/stripe-go/v74 v74.29.0
|
||||
@@ -63,33 +66,39 @@ require (
|
||||
github.com/xorm-io/builder v0.3.13
|
||||
github.com/xorm-io/core v0.7.4
|
||||
github.com/xorm-io/xorm v1.1.6
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/oauth2 v0.17.0
|
||||
golang.org/x/text v0.26.0
|
||||
google.golang.org/api v0.150.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.27.0
|
||||
golang.org/x/text v0.27.0
|
||||
google.golang.org/api v0.215.0
|
||||
layeh.com/radius v0.0.0-20231213012653-1006025d24f8
|
||||
maunium.net/go/mautrix v0.16.0
|
||||
maunium.net/go/mautrix v0.22.1
|
||||
modernc.org/sqlite v1.18.2
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.8 // indirect
|
||||
cloud.google.com/go/compute v1.23.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.3 // indirect
|
||||
cloud.google.com/go/storage v1.35.1 // indirect
|
||||
cel.dev/expr v0.18.0 // indirect
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/auth v0.13.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/iam v1.2.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.2 // indirect
|
||||
cloud.google.com/go/storage v1.47.0 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
|
||||
github.com/Azure/azure-storage-blob-go v0.15.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9 // indirect
|
||||
github.com/SherClockHolmes/webpush-go v1.2.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20240116134246-a8cbe886bab0 // indirect
|
||||
github.com/SherClockHolmes/webpush-go v1.4.0 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||
github.com/alibabacloud-go/darabonba-number v1.0.4 // indirect
|
||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||
@@ -105,34 +114,44 @@ require (
|
||||
github.com/aliyun/credentials-go v1.3.10 // indirect
|
||||
github.com/apistd/uni-go-sdk v0.0.2 // indirect
|
||||
github.com/atc0005/go-teams-notify/v2 v2.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.45.5 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.156 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/bwmarrin/discordgo v0.27.1 // indirect
|
||||
github.com/blinkbean/dingtalk v1.1.3 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bwmarrin/discordgo v0.28.1 // indirect
|
||||
github.com/caarlos0/go-reddit/v3 v3.0.1 // indirect
|
||||
github.com/casdoor/casdoor-go-sdk v0.50.0 // indirect
|
||||
github.com/casdoor/go-reddit/v2 v2.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/dghubble/oauth1 v0.7.2 // indirect
|
||||
github.com/dghubble/sling v1.4.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/dghubble/oauth1 v0.7.3 // indirect
|
||||
github.com/dghubble/sling v1.4.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/di-wu/parser v0.2.2 // indirect
|
||||
github.com/di-wu/xsd-datetime v1.0.0 // indirect
|
||||
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7 // indirect
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.9.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
|
||||
github.com/ggicci/httpin v0.19.0 // indirect
|
||||
github.com/ggicci/owl v0.8.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||
github.com/go-lark/lark v1.9.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-lark/lark v1.15.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-pay/crypto v0.0.1 // indirect
|
||||
github.com/go-pay/errgroup v0.0.3 // indirect
|
||||
@@ -140,23 +159,20 @@ require (
|
||||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-webauthn/x v0.1.9 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.0 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/gregdel/pushover v1.2.1 // indirect
|
||||
github.com/google/s2a-go v0.1.8 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gregdel/pushover v1.3.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
@@ -167,17 +183,17 @@ require (
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/markbates/going v1.0.0 // indirect
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mileusna/viber v1.0.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -186,14 +202,17 @@ require (
|
||||
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
|
||||
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
|
||||
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.30.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/qiniu/go-sdk/v7 v7.12.1 // indirect
|
||||
github.com/redis/go-redis/v9 v9.5.5 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/scim2/filter-parser/v2 v2.2.0 // indirect
|
||||
github.com/sendgrid/rest v2.6.9+incompatible // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
@@ -201,61 +220,66 @@ require (
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/slack-go/slack v0.12.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/slack-go/slack v0.15.0 // indirect
|
||||
github.com/spyzhov/ajson v0.8.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.744 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.744 // indirect
|
||||
github.com/tidwall/gjson v1.16.0 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/twilio/twilio-go v1.13.0 // indirect
|
||||
github.com/ucloud/ucloud-sdk-go v0.22.5 // indirect
|
||||
github.com/utahta/go-linenotify v0.5.0 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.117 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.mau.fi/util v0.0.0-20230805171708-199bf3eec776 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.mau.fi/util v0.8.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
|
||||
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
|
||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||
google.golang.org/grpc v1.68.0 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
maunium.net/go/maulogger/v2 v2.4.1 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.37.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.9 // indirect
|
||||
modernc.org/libc v1.18.0 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.3.0 // indirect
|
||||
modernc.org/opt v0.1.1 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -141,10 +141,26 @@ func parseAllWords(category string) *I18nData {
|
||||
return &data
|
||||
}
|
||||
|
||||
// copyI18nData creates a deep copy of an I18nData structure to prevent shared reference issues
|
||||
// between language translations. This ensures each language starts with fresh English defaults
|
||||
// rather than inheriting values from previously processed languages.
|
||||
func copyI18nData(src *I18nData) *I18nData {
|
||||
dst := I18nData{}
|
||||
for namespace, pairs := range *src {
|
||||
dst[namespace] = make(map[string]string)
|
||||
for key, value := range pairs {
|
||||
dst[namespace][key] = value
|
||||
}
|
||||
}
|
||||
return &dst
|
||||
}
|
||||
|
||||
func applyToOtherLanguage(category string, language string, newData *I18nData) {
|
||||
oldData := readI18nFile(category, language)
|
||||
println(oldData)
|
||||
|
||||
applyData(newData, oldData)
|
||||
writeI18nFile(category, language, newData)
|
||||
// Create a copy of newData to avoid modifying the shared data across languages
|
||||
dataCopy := copyI18nData(newData)
|
||||
applyData(dataCopy, oldData)
|
||||
writeI18nFile(category, language, dataCopy)
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ type CustomUserInfo struct {
|
||||
DisplayName string `mapstructure:"displayName"`
|
||||
Email string `mapstructure:"email"`
|
||||
AvatarUrl string `mapstructure:"avatarUrl"`
|
||||
Phone string `mapstructure:"phone"`
|
||||
}
|
||||
|
||||
func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
@@ -153,6 +154,7 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
Username: customUserinfo.Username,
|
||||
DisplayName: customUserinfo.DisplayName,
|
||||
Email: customUserinfo.Email,
|
||||
Phone: customUserinfo.Phone,
|
||||
AvatarUrl: customUserinfo.AvatarUrl,
|
||||
}
|
||||
return userInfo, nil
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -65,7 +66,7 @@ func (idp *TelegramIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
}
|
||||
|
||||
// Create a token with the user ID as access token
|
||||
userId, ok := authData["id"].(float64)
|
||||
userId, ok := telegramAsInt64(authData["id"])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid user id in auth data")
|
||||
}
|
||||
@@ -77,7 +78,7 @@ func (idp *TelegramIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
}
|
||||
|
||||
token := &oauth2.Token{
|
||||
AccessToken: fmt.Sprintf("telegram_%d", int64(userId)),
|
||||
AccessToken: fmt.Sprintf("telegram_%d", userId),
|
||||
TokenType: "Bearer",
|
||||
}
|
||||
|
||||
@@ -97,6 +98,7 @@ func (idp *TelegramIdProvider) verifyTelegramAuth(authData map[string]interface{
|
||||
if !ok {
|
||||
return fmt.Errorf("hash not found in auth data")
|
||||
}
|
||||
hash = strings.TrimSpace(hash)
|
||||
|
||||
// Prepare data check string
|
||||
var dataCheckArr []string
|
||||
@@ -104,13 +106,14 @@ func (idp *TelegramIdProvider) verifyTelegramAuth(authData map[string]interface{
|
||||
if key == "hash" {
|
||||
continue
|
||||
}
|
||||
dataCheckArr = append(dataCheckArr, fmt.Sprintf("%s=%v", key, value))
|
||||
dataCheckArr = append(dataCheckArr, fmt.Sprintf("%s=%s", key, telegramAsString(value)))
|
||||
}
|
||||
sort.Strings(dataCheckArr)
|
||||
dataCheckString := strings.Join(dataCheckArr, "\n")
|
||||
|
||||
// Calculate secret key
|
||||
secretKey := sha256.Sum256([]byte(idp.ClientSecret))
|
||||
clientSecret := strings.TrimSpace(idp.ClientSecret)
|
||||
secretKey := sha256.Sum256([]byte(clientSecret))
|
||||
|
||||
// Calculate hash
|
||||
h := hmac.New(sha256.New, secretKey[:])
|
||||
@@ -139,7 +142,7 @@ func (idp *TelegramIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
}
|
||||
|
||||
// Extract user information from auth data
|
||||
userId, ok := authData["id"].(float64)
|
||||
userId, ok := telegramAsInt64(authData["id"])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid user id in auth data")
|
||||
}
|
||||
@@ -155,11 +158,11 @@ func (idp *TelegramIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
displayName = username
|
||||
}
|
||||
if displayName == "" {
|
||||
displayName = strconv.FormatInt(int64(userId), 10)
|
||||
displayName = strconv.FormatInt(userId, 10)
|
||||
}
|
||||
|
||||
userInfo := UserInfo{
|
||||
Id: strconv.FormatInt(int64(userId), 10),
|
||||
Id: strconv.FormatInt(userId, 10),
|
||||
Username: username,
|
||||
DisplayName: displayName,
|
||||
AvatarUrl: photoUrl,
|
||||
@@ -167,3 +170,38 @@ func (idp *TelegramIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
func telegramAsInt64(v interface{}) (int64, bool) {
|
||||
switch t := v.(type) {
|
||||
case float64:
|
||||
if t != math.Trunc(t) {
|
||||
return 0, false
|
||||
}
|
||||
if t > float64(math.MaxInt64) || t < float64(math.MinInt64) {
|
||||
return 0, false
|
||||
}
|
||||
return int64(t), true
|
||||
case string:
|
||||
i, err := strconv.ParseInt(t, 10, 64)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return i, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func telegramAsString(v interface{}) string {
|
||||
switch t := v.(type) {
|
||||
case string:
|
||||
return t
|
||||
case float64:
|
||||
if t == math.Trunc(t) && t <= float64(math.MaxInt64) && t >= float64(math.MinInt64) {
|
||||
return strconv.FormatInt(int64(t), 10)
|
||||
}
|
||||
return strconv.FormatFloat(t, 'g', -1, 64)
|
||||
default:
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
}
|
||||
|
||||
111
idv/aliyun.go
Normal file
111
idv/aliyun.go
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2025 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 idv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cloudauth "github.com/alibabacloud-go/cloudauth-20190307/v3/client"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultAlibabaCloudEndpoint is the default endpoint for Alibaba Cloud ID verification service
|
||||
DefaultAlibabaCloudEndpoint = "cloudauth.cn-shanghai.aliyuncs.com"
|
||||
)
|
||||
|
||||
type AlibabaCloudIdvProvider struct {
|
||||
ClientId string
|
||||
ClientSecret string
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
func NewAlibabaCloudIdvProvider(clientId string, clientSecret string, endpoint string) *AlibabaCloudIdvProvider {
|
||||
return &AlibabaCloudIdvProvider{
|
||||
ClientId: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (provider *AlibabaCloudIdvProvider) VerifyIdentity(idCardType string, idCard string, realName string) (bool, error) {
|
||||
if provider.ClientId == "" || provider.ClientSecret == "" {
|
||||
return false, fmt.Errorf("Alibaba Cloud credentials not configured")
|
||||
}
|
||||
|
||||
if idCard == "" || realName == "" {
|
||||
return false, fmt.Errorf("ID card and real name are required")
|
||||
}
|
||||
|
||||
// Default endpoint if not configured
|
||||
endpoint := provider.Endpoint
|
||||
if endpoint == "" {
|
||||
endpoint = DefaultAlibabaCloudEndpoint
|
||||
}
|
||||
|
||||
// Create client configuration
|
||||
config := &openapi.Config{
|
||||
AccessKeyId: tea.String(provider.ClientId),
|
||||
AccessKeySecret: tea.String(provider.ClientSecret),
|
||||
Endpoint: tea.String(endpoint),
|
||||
}
|
||||
|
||||
// Create Alibaba Cloud Auth client
|
||||
client, err := cloudauth.NewClient(config)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to create Alibaba Cloud client: %v", err)
|
||||
}
|
||||
|
||||
// Prepare verification request using Id2MetaVerify API
|
||||
// This API verifies Chinese ID card number and real name
|
||||
// Reference: https://help.aliyun.com/zh/id-verification/financial-grade-id-verification/server-side-integration-2
|
||||
request := &cloudauth.Id2MetaVerifyRequest{
|
||||
IdentifyNum: tea.String(idCard),
|
||||
UserName: tea.String(realName),
|
||||
ParamType: tea.String("normal"),
|
||||
}
|
||||
|
||||
// Send verification request
|
||||
response, err := client.Id2MetaVerify(request)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to verify identity with Alibaba Cloud: %v", err)
|
||||
}
|
||||
|
||||
// Check response
|
||||
if response == nil || response.Body == nil {
|
||||
return false, fmt.Errorf("empty response from Alibaba Cloud")
|
||||
}
|
||||
|
||||
// Check if the API call was successful
|
||||
if response.Body.Code == nil || *response.Body.Code != "200" {
|
||||
message := "unknown error"
|
||||
if response.Body.Message != nil {
|
||||
message = *response.Body.Message
|
||||
}
|
||||
return false, fmt.Errorf("Alibaba Cloud API error: %s", message)
|
||||
}
|
||||
|
||||
// Check verification result
|
||||
// BizCode "1" means verification passed
|
||||
if response.Body.ResultObject != nil && response.Body.ResultObject.BizCode != nil {
|
||||
if *response.Body.ResultObject.BizCode == "1" {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("identity verification failed: BizCode=%s", *response.Body.ResultObject.BizCode)
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("identity verification failed: missing result")
|
||||
}
|
||||
143
idv/jumio.go
Normal file
143
idv/jumio.go
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2025 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 idv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type JumioIdvProvider struct {
|
||||
ClientId string
|
||||
ClientSecret string
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
type JumioInitiateRequest struct {
|
||||
CustomerInternalReference string `json:"customerInternalReference"`
|
||||
UserReference string `json:"userReference"`
|
||||
WorkflowId string `json:"workflowId,omitempty"`
|
||||
}
|
||||
|
||||
type JumioInitiateResponse struct {
|
||||
TransactionReference string `json:"transactionReference"`
|
||||
RedirectUrl string `json:"redirectUrl"`
|
||||
}
|
||||
|
||||
type JumioVerificationData struct {
|
||||
IdCard string `json:"idNumber"`
|
||||
RealName string `json:"firstName"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func NewJumioIdvProvider(clientId string, clientSecret string, endpoint string) *JumioIdvProvider {
|
||||
return &JumioIdvProvider{
|
||||
ClientId: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (provider *JumioIdvProvider) VerifyIdentity(idCardType string, idCard string, realName string) (bool, error) {
|
||||
if provider.ClientId == "" || provider.ClientSecret == "" {
|
||||
return false, fmt.Errorf("Jumio credentials not configured")
|
||||
}
|
||||
|
||||
if provider.Endpoint == "" {
|
||||
return false, fmt.Errorf("Jumio endpoint not configured")
|
||||
}
|
||||
|
||||
if idCard == "" || realName == "" {
|
||||
return false, fmt.Errorf("ID card and real name are required")
|
||||
}
|
||||
|
||||
// Jumio ID Verification implementation
|
||||
// This implementation follows Jumio's API workflow:
|
||||
// 1. Initiate a verification session
|
||||
// 2. User would normally go through verification flow (redirected to Jumio)
|
||||
// 3. Check verification status
|
||||
// For automated verification, we simulate the process
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
// Prepare the initiation request
|
||||
initiateReq := JumioInitiateRequest{
|
||||
CustomerInternalReference: fmt.Sprintf("user_%s", idCard),
|
||||
UserReference: realName,
|
||||
}
|
||||
|
||||
reqBody, err := json.Marshal(initiateReq)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to marshal request: %v", err)
|
||||
}
|
||||
|
||||
// Create HTTP request to Jumio API
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s/api/v4/initiate", provider.Endpoint), bytes.NewBuffer(reqBody))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to create request: %v", err)
|
||||
}
|
||||
|
||||
// Set authentication headers
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", "Casdoor/1.0")
|
||||
req.SetBasicAuth(provider.ClientId, provider.ClientSecret)
|
||||
|
||||
// Send request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to send request to Jumio: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read response: %v", err)
|
||||
}
|
||||
|
||||
// Check response status
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
||||
return false, fmt.Errorf("Jumio API returned error status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var initiateResp JumioInitiateResponse
|
||||
if err := json.Unmarshal(body, &initiateResp); err != nil {
|
||||
return false, fmt.Errorf("failed to parse Jumio response: %v", err)
|
||||
}
|
||||
|
||||
// In a real implementation, the user would be redirected to initiateResp.RedirectUrl
|
||||
// to complete the verification process. Here we simulate successful verification.
|
||||
// For production, you would need to:
|
||||
// 1. Store the transaction reference
|
||||
// 2. Redirect user to RedirectUrl or provide it to them
|
||||
// 3. Implement a webhook to receive verification results
|
||||
// 4. Query the transaction status using the transaction reference
|
||||
|
||||
// Simulate verification check (in production, this would be a webhook callback or status query)
|
||||
if initiateResp.TransactionReference != "" {
|
||||
// Successfully initiated verification session
|
||||
// In a real scenario, return would depend on actual verification completion
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("verification could not be initiated")
|
||||
}
|
||||
29
idv/provider.go
Normal file
29
idv/provider.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2025 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 idv
|
||||
|
||||
type IdvProvider interface {
|
||||
VerifyIdentity(idCardType string, idCard string, realName string) (bool, error)
|
||||
}
|
||||
|
||||
func GetIdvProvider(typ string, clientId string, clientSecret string, endpoint string) IdvProvider {
|
||||
if typ == "Jumio" {
|
||||
return NewJumioIdvProvider(clientId, clientSecret, endpoint)
|
||||
} else if typ == "Alibaba Cloud" {
|
||||
return NewAlibabaCloudIdvProvider(clientId, clientSecret, endpoint)
|
||||
}
|
||||
// Default to Jumio for backward compatibility
|
||||
return NewJumioIdvProvider(clientId, clientSecret, endpoint)
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"displayName": "",
|
||||
"websiteUrl": "",
|
||||
"favicon": "",
|
||||
"passwordType": "plain",
|
||||
"passwordType": "bcrypt",
|
||||
"passwordSalt": "",
|
||||
"passwordOptions": [
|
||||
"AtLeast6"
|
||||
@@ -76,7 +76,44 @@
|
||||
"enableSoftDeletion": false,
|
||||
"isProfilePublic": true,
|
||||
"disableSignin": false,
|
||||
"accountItems": []
|
||||
"accountItems": [
|
||||
{"name": "Organization", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "ID", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Name", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Display name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Avatar", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "User type", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Password", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Email", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Phone", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Country code", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Country/Region", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Location", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Affiliation", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Title", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID card type", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID card", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Real name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID verification", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Homepage", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Bio", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Tag", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Signup application", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Register type", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Register source", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Roles", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Permissions", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Groups", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "3rd-party logins", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Properties", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Is admin", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Is forbidden", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Is deleted", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Multi-factor authentication", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "WebAuthn credentials", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Managed accounts", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "MFA accounts", "visible": true, "viewRule": "Self", "modifyRule": "Self"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
|
||||
@@ -281,7 +281,7 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
|
||||
}
|
||||
return filteredUsers, ldap.LDAPResultSuccess
|
||||
}
|
||||
if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
|
||||
if m.Client.IsGlobalAdmin || (m.Client.IsOrgAdmin && org == m.Client.OrgName) {
|
||||
filteredUsers, err = object.GetUsersWithFilter(org, buildSafeCondition(r.Filter()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -349,7 +349,7 @@ func GetFilteredGroups(m *ldap.Message, baseDN string, filterStr string) ([]*obj
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
|
||||
} else if m.Client.IsGlobalAdmin || (m.Client.IsOrgAdmin && org == m.Client.OrgName) {
|
||||
groups, err = object.GetGroups(org)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
65
main.go
65
main.go
@@ -18,9 +18,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/beego/beego/logs"
|
||||
_ "github.com/beego/beego/session/redis"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
_ "github.com/beego/beego/v2/server/web/session/redis"
|
||||
"github.com/casdoor/casdoor/authz"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/controllers"
|
||||
@@ -33,6 +33,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
web.BConfig.WebConfig.Session.SessionOn = true
|
||||
web.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
||||
if conf.GetConfigString("redisEndpoint") == "" {
|
||||
web.BConfig.WebConfig.Session.SessionProvider = "file"
|
||||
web.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp"
|
||||
} else {
|
||||
web.BConfig.WebConfig.Session.SessionProvider = "redis"
|
||||
web.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
|
||||
}
|
||||
web.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
|
||||
web.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 30
|
||||
// web.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
|
||||
|
||||
routers.InitAPI()
|
||||
object.InitFlag()
|
||||
object.InitAdapter()
|
||||
object.CreateTables()
|
||||
@@ -62,35 +76,22 @@ func main() {
|
||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||
util.SafeGoroutine(func() { controllers.InitCLIDownloader() })
|
||||
|
||||
// beego.DelStaticPath("/static")
|
||||
// beego.SetStaticPath("/static", "web/build/static")
|
||||
// web.DelStaticPath("/static")
|
||||
// web.SetStaticPath("/static", "web/build/static")
|
||||
|
||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||
beego.SetStaticPath("/swagger", "swagger")
|
||||
beego.SetStaticPath("/files", "files")
|
||||
web.BConfig.WebConfig.DirectoryIndex = true
|
||||
web.SetStaticPath("/swagger", "swagger")
|
||||
web.SetStaticPath("/files", "files")
|
||||
// https://studygolang.com/articles/2303
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.TimeoutFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.FieldValidationFilter)
|
||||
beego.InsertFilter("*", beego.AfterExec, routers.AfterRecordMessage, false)
|
||||
|
||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
||||
if conf.GetConfigString("redisEndpoint") == "" {
|
||||
beego.BConfig.WebConfig.Session.SessionProvider = "file"
|
||||
beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp"
|
||||
} else {
|
||||
beego.BConfig.WebConfig.Session.SessionProvider = "redis"
|
||||
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
|
||||
}
|
||||
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
|
||||
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 30
|
||||
// beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.StaticFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.AutoSigninFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.CorsFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.TimeoutFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.ApiFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.PrometheusFilter)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.RecordMessage)
|
||||
web.InsertFilter("*", web.BeforeRouter, routers.FieldValidationFilter)
|
||||
web.InsertFilter("*", web.AfterExec, routers.AfterRecordMessage, web.WithReturnOnOutput(false))
|
||||
|
||||
var logAdapter string
|
||||
logConfigMap := make(map[string]interface{})
|
||||
@@ -112,7 +113,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
port := beego.AppConfig.DefaultInt("httpport", 8000)
|
||||
port := web.AppConfig.DefaultInt("httpport", 8000)
|
||||
// logs.SetLevel(logs.LevelInformational)
|
||||
logs.SetLogFuncCall(false)
|
||||
|
||||
@@ -125,5 +126,5 @@ func main() {
|
||||
go radius.StartRadiusServer()
|
||||
go object.ClearThroughputPerSecond()
|
||||
|
||||
beego.Run(fmt.Sprintf(":%v", port))
|
||||
web.Run(fmt.Sprintf(":%v", port))
|
||||
}
|
||||
|
||||
117
mcp/application.go
Normal file
117
mcp/application.go
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 2026 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 mcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// handleGetApplicationsTool handles the get_applications MCP tool
|
||||
func (c *McpController) handleGetApplicationsTool(id interface{}, args GetApplicationsArgs) {
|
||||
userId := c.GetSessionUsername()
|
||||
|
||||
applications, err := object.GetApplications(args.Owner)
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
maskedApps := object.GetMaskedApplications(applications, userId)
|
||||
c.SendToolResult(id, util.StructToJsonFormatted(maskedApps))
|
||||
}
|
||||
|
||||
// handleGetApplicationTool handles the get_application MCP tool
|
||||
func (c *McpController) handleGetApplicationTool(id interface{}, args GetApplicationArgs) {
|
||||
userId := c.GetSessionUsername()
|
||||
|
||||
application, err := object.GetApplication(args.Id)
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
maskedApp := object.GetMaskedApplication(application, userId)
|
||||
c.SendToolResult(id, util.StructToJsonFormatted(maskedApp))
|
||||
}
|
||||
|
||||
// handleAddApplicationTool handles the add_application MCP tool
|
||||
func (c *McpController) handleAddApplicationTool(id interface{}, args AddApplicationArgs) {
|
||||
count, err := object.GetApplicationCount("", "", "")
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkQuotaForApplication(int(count)); err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err = object.CheckIpWhitelist(args.Application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.AddApplication(&args.Application)
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.SendToolResult(id, FormatOperationResult("add", "application", affected))
|
||||
}
|
||||
|
||||
// handleUpdateApplicationTool handles the update_application MCP tool
|
||||
func (c *McpController) handleUpdateApplicationTool(id interface{}, args UpdateApplicationArgs) {
|
||||
if err := object.CheckIpWhitelist(args.Application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.UpdateApplication(args.Id, &args.Application, c.IsGlobalAdmin(), c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.SendToolResult(id, FormatOperationResult("update", "application", affected))
|
||||
}
|
||||
|
||||
// handleDeleteApplicationTool handles the delete_application MCP tool
|
||||
func (c *McpController) handleDeleteApplicationTool(id interface{}, args DeleteApplicationArgs) {
|
||||
affected, err := object.DeleteApplication(&args.Application)
|
||||
if err != nil {
|
||||
c.SendToolErrorResult(id, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.SendToolResult(id, FormatOperationResult("delete", "application", affected))
|
||||
}
|
||||
|
||||
// checkQuotaForApplication checks if the application quota is exceeded
|
||||
func checkQuotaForApplication(count int) error {
|
||||
quota := conf.GetConfigQuota().Application
|
||||
if quota == -1 {
|
||||
return nil
|
||||
}
|
||||
if count >= quota {
|
||||
return fmt.Errorf("application quota is exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
115
mcp/auth.go
Normal file
115
mcp/auth.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2026 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 mcp
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// SessionData represents session metadata
|
||||
type SessionData struct {
|
||||
ExpireTime int64
|
||||
}
|
||||
|
||||
// GetSessionUsername returns the username from session
|
||||
func (c *McpController) GetSessionUsername() string {
|
||||
// check if user session expired
|
||||
sessionData := c.GetSessionData()
|
||||
|
||||
if sessionData != nil &&
|
||||
sessionData.ExpireTime != 0 &&
|
||||
sessionData.ExpireTime < time.Now().Unix() {
|
||||
c.ClearUserSession()
|
||||
return ""
|
||||
}
|
||||
|
||||
user := c.GetSession("username")
|
||||
if user == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return user.(string)
|
||||
}
|
||||
|
||||
// GetSessionData retrieves session data
|
||||
func (c *McpController) GetSessionData() *SessionData {
|
||||
session := c.GetSession("SessionData")
|
||||
if session == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
sessionData := &SessionData{}
|
||||
err := util.JsonToStruct(session.(string), sessionData)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return sessionData
|
||||
}
|
||||
|
||||
// ClearUserSession clears the user session
|
||||
func (c *McpController) ClearUserSession() {
|
||||
c.SetSession("username", "")
|
||||
c.DelSession("SessionData")
|
||||
_ = c.SessionRegenerateID()
|
||||
}
|
||||
|
||||
// IsGlobalAdmin checks if the current user is a global admin
|
||||
func (c *McpController) IsGlobalAdmin() bool {
|
||||
isGlobalAdmin, _ := c.isGlobalAdmin()
|
||||
return isGlobalAdmin
|
||||
}
|
||||
|
||||
func (c *McpController) isGlobalAdmin() (bool, *object.User) {
|
||||
username := c.GetSessionUsername()
|
||||
if object.IsAppUser(username) {
|
||||
// e.g., "app/app-casnode"
|
||||
return true, nil
|
||||
}
|
||||
|
||||
user := c.getCurrentUser()
|
||||
if user == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return user.IsGlobalAdmin(), user
|
||||
}
|
||||
|
||||
func (c *McpController) getCurrentUser() *object.User {
|
||||
var user *object.User
|
||||
var err error
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
user = nil
|
||||
} else {
|
||||
user, err = object.GetUser(userId)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
// GetAcceptLanguage returns the Accept-Language header value
|
||||
func (c *McpController) GetAcceptLanguage() string {
|
||||
language := c.Ctx.Request.Header.Get("Accept-Language")
|
||||
if len(language) > 2 {
|
||||
language = language[0:2]
|
||||
}
|
||||
return language
|
||||
}
|
||||
407
mcp/base.go
Normal file
407
mcp/base.go
Normal file
@@ -0,0 +1,407 @@
|
||||
// Copyright 2026 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 mcp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
)
|
||||
|
||||
// MCP JSON-RPC 2.0 structures
|
||||
type McpRequest struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id"`
|
||||
Method string `json:"method"`
|
||||
Params json.RawMessage `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
type McpResponse struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
Error *McpError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type McpError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type McpInitializeParams struct {
|
||||
ProtocolVersion string `json:"protocolVersion"`
|
||||
Capabilities map[string]interface{} `json:"capabilities"`
|
||||
ClientInfo McpImplementation `json:"clientInfo"`
|
||||
}
|
||||
|
||||
type McpImplementation struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type McpInitializeResult struct {
|
||||
ProtocolVersion string `json:"protocolVersion"`
|
||||
Capabilities McpServerCapabilities `json:"capabilities"`
|
||||
ServerInfo McpImplementation `json:"serverInfo"`
|
||||
}
|
||||
|
||||
type McpServerCapabilities struct {
|
||||
Tools map[string]interface{} `json:"tools,omitempty"`
|
||||
}
|
||||
|
||||
type McpListToolsResult struct {
|
||||
Tools []McpTool `json:"tools"`
|
||||
}
|
||||
|
||||
type McpTool struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
InputSchema map[string]interface{} `json:"inputSchema"`
|
||||
}
|
||||
|
||||
type McpCallToolParams struct {
|
||||
Name string `json:"name"`
|
||||
Arguments json.RawMessage `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
// Tool-specific argument structs
|
||||
type GetApplicationsArgs struct {
|
||||
Owner string `json:"owner"`
|
||||
}
|
||||
|
||||
type GetApplicationArgs struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type AddApplicationArgs struct {
|
||||
Application object.Application `json:"application"`
|
||||
}
|
||||
|
||||
type UpdateApplicationArgs struct {
|
||||
Id string `json:"id"`
|
||||
Application object.Application `json:"application"`
|
||||
}
|
||||
|
||||
type DeleteApplicationArgs struct {
|
||||
Application object.Application `json:"application"`
|
||||
}
|
||||
|
||||
type McpCallToolResult struct {
|
||||
Content []TextContent `json:"content"`
|
||||
IsError bool `json:"isError,omitempty"`
|
||||
}
|
||||
|
||||
type TextContent struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// MCPController handles MCP protocol requests
|
||||
type McpController struct {
|
||||
web.Controller
|
||||
}
|
||||
|
||||
func (c *McpController) Prepare() {
|
||||
c.EnableRender = false
|
||||
}
|
||||
|
||||
// SendMcpResponse sends a successful MCP response
|
||||
func (c *McpController) SendMcpResponse(id interface{}, result interface{}) {
|
||||
resp := GetMcpResponse(id, result, nil)
|
||||
|
||||
// Set proper HTTP headers for MCP responses
|
||||
c.Ctx.Output.Header("Content-Type", "application/json")
|
||||
c.Data["json"] = resp
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// SendMcpError sends an MCP error response
|
||||
func (c *McpController) SendMcpError(id interface{}, code int, message string, data interface{}) {
|
||||
resp := GetMcpResponse(id, nil, &McpError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
|
||||
// Set proper HTTP headers for MCP responses
|
||||
c.Ctx.Output.Header("Content-Type", "application/json")
|
||||
c.Data["json"] = resp
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetMcpResponse returns a McpResponse object
|
||||
func GetMcpResponse(id interface{}, result interface{}, err *McpError) McpResponse {
|
||||
resp := McpResponse{
|
||||
JSONRPC: "2.0",
|
||||
ID: id,
|
||||
Result: result,
|
||||
Error: err,
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// sendInvalidParamsError sends an invalid params error
|
||||
func (c *McpController) sendInvalidParamsError(id interface{}, details string) {
|
||||
c.SendMcpError(id, -32602, "Invalid params", details)
|
||||
}
|
||||
|
||||
// SendToolResult sends a successful tool execution result
|
||||
func (c *McpController) SendToolResult(id interface{}, text string) {
|
||||
result := McpCallToolResult{
|
||||
Content: []TextContent{
|
||||
{
|
||||
Type: "text",
|
||||
Text: text,
|
||||
},
|
||||
},
|
||||
}
|
||||
c.SendMcpResponse(id, result)
|
||||
}
|
||||
|
||||
// SendToolErrorResult sends a tool execution error result
|
||||
func (c *McpController) SendToolErrorResult(id interface{}, errorMsg string) {
|
||||
result := McpCallToolResult{
|
||||
Content: []TextContent{
|
||||
{
|
||||
Type: "text",
|
||||
Text: errorMsg,
|
||||
},
|
||||
},
|
||||
IsError: true,
|
||||
}
|
||||
c.SendMcpResponse(id, result)
|
||||
}
|
||||
|
||||
// FormatOperationResult formats the result of CRUD operations in a clear, descriptive way
|
||||
func FormatOperationResult(operation, resourceType string, affected bool) string {
|
||||
if affected {
|
||||
// Map operation to past tense
|
||||
pastTense := operation + "d"
|
||||
if operation == "add" {
|
||||
pastTense = "added"
|
||||
} else if operation == "update" {
|
||||
pastTense = "updated"
|
||||
} else if operation == "delete" {
|
||||
pastTense = "deleted"
|
||||
}
|
||||
return fmt.Sprintf("Successfully %s %s", pastTense, resourceType)
|
||||
}
|
||||
return fmt.Sprintf("No changes were made to %s (may already exist or not found)", resourceType)
|
||||
}
|
||||
|
||||
// HandleMcp handles MCP protocol requests
|
||||
// @Title HandleMcp
|
||||
// @Tag MCP API
|
||||
// @Description handle MCP (Model Context Protocol) requests
|
||||
// @Success 200 {object} McpResponse The Response object
|
||||
// @router /mcp [post]
|
||||
func (c *McpController) HandleMcp() {
|
||||
var req McpRequest
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
|
||||
if err != nil {
|
||||
c.SendMcpError(nil, -32700, "Parse error", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Handle different MCP methods
|
||||
switch req.Method {
|
||||
case "initialize":
|
||||
c.handleInitialize(req)
|
||||
case "notifications/initialized":
|
||||
c.handleNotificationsInitialized(req)
|
||||
case "ping":
|
||||
c.handlePing(req)
|
||||
case "tools/list":
|
||||
c.handleToolsList(req)
|
||||
case "tools/call":
|
||||
c.handleToolsCall(req)
|
||||
default:
|
||||
c.SendMcpError(req.ID, -32601, "Method not found", fmt.Sprintf("Method '%s' not found", req.Method))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *McpController) handleInitialize(req McpRequest) {
|
||||
var params McpInitializeParams
|
||||
if req.Params != nil {
|
||||
err := json.Unmarshal(req.Params, ¶ms)
|
||||
if err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result := McpInitializeResult{
|
||||
ProtocolVersion: "2024-11-05",
|
||||
Capabilities: McpServerCapabilities{
|
||||
Tools: map[string]interface{}{
|
||||
"listChanged": true,
|
||||
},
|
||||
},
|
||||
ServerInfo: McpImplementation{
|
||||
Name: "Casdoor MCP Server",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
}
|
||||
|
||||
c.SendMcpResponse(req.ID, result)
|
||||
}
|
||||
|
||||
func (c *McpController) handleNotificationsInitialized(req McpRequest) {
|
||||
c.Ctx.Output.SetStatus(202)
|
||||
}
|
||||
|
||||
func (c *McpController) handlePing(req McpRequest) {
|
||||
// ping method is used to check if the server is alive and responsive
|
||||
// Return an empty object as result to indicate server is active
|
||||
c.SendMcpResponse(req.ID, map[string]interface{}{})
|
||||
}
|
||||
|
||||
func (c *McpController) handleToolsList(req McpRequest) {
|
||||
tools := []McpTool{
|
||||
{
|
||||
Name: "get_applications",
|
||||
Description: "Get all applications for a specific owner",
|
||||
InputSchema: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"owner": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "The owner of applications",
|
||||
},
|
||||
},
|
||||
"required": []string{"owner"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "get_application",
|
||||
Description: "Get the detail of a specific application",
|
||||
InputSchema: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"id": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "The id (owner/name) of the application",
|
||||
},
|
||||
},
|
||||
"required": []string{"id"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "add_application",
|
||||
Description: "Add a new application",
|
||||
InputSchema: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"application": map[string]interface{}{
|
||||
"type": "object",
|
||||
"description": "The application object to add",
|
||||
},
|
||||
},
|
||||
"required": []string{"application"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update_application",
|
||||
Description: "Update an existing application",
|
||||
InputSchema: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"id": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "The id (owner/name) of the application",
|
||||
},
|
||||
"application": map[string]interface{}{
|
||||
"type": "object",
|
||||
"description": "The updated application object",
|
||||
},
|
||||
},
|
||||
"required": []string{"id", "application"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "delete_application",
|
||||
Description: "Delete an application",
|
||||
InputSchema: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"application": map[string]interface{}{
|
||||
"type": "object",
|
||||
"description": "The application object to delete",
|
||||
},
|
||||
},
|
||||
"required": []string{"application"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result := McpListToolsResult{
|
||||
Tools: tools,
|
||||
}
|
||||
|
||||
c.SendMcpResponse(req.ID, result)
|
||||
}
|
||||
|
||||
func (c *McpController) handleToolsCall(req McpRequest) {
|
||||
var params McpCallToolParams
|
||||
err := json.Unmarshal(req.Params, ¶ms)
|
||||
if err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Route to the appropriate tool handler
|
||||
switch params.Name {
|
||||
case "get_applications":
|
||||
var args GetApplicationsArgs
|
||||
if err := json.Unmarshal(params.Arguments, &args); err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
c.handleGetApplicationsTool(req.ID, args)
|
||||
case "get_application":
|
||||
var args GetApplicationArgs
|
||||
if err := json.Unmarshal(params.Arguments, &args); err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
c.handleGetApplicationTool(req.ID, args)
|
||||
case "add_application":
|
||||
var args AddApplicationArgs
|
||||
if err := json.Unmarshal(params.Arguments, &args); err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
c.handleAddApplicationTool(req.ID, args)
|
||||
case "update_application":
|
||||
var args UpdateApplicationArgs
|
||||
if err := json.Unmarshal(params.Arguments, &args); err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
c.handleUpdateApplicationTool(req.ID, args)
|
||||
case "delete_application":
|
||||
var args DeleteApplicationArgs
|
||||
if err := json.Unmarshal(params.Arguments, &args); err != nil {
|
||||
c.sendInvalidParamsError(req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
c.handleDeleteApplicationTool(req.ID, args)
|
||||
default:
|
||||
c.SendMcpError(req.ID, -32602, "Invalid tool name", fmt.Sprintf("Tool '%s' not found", params.Name))
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/bark"
|
||||
"github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/bark"
|
||||
)
|
||||
|
||||
func NewBarkProvider(deviceKey string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/cucloud"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/cucloud"
|
||||
)
|
||||
|
||||
func NewCucloudProvider(accessKey, secretKey, topicName, messageTitle, cloudRegionCode, accountId, notifyType string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/dingding"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/dingding"
|
||||
)
|
||||
|
||||
func NewDingTalkProvider(token string, secret string) (notify.Notifier, error) {
|
||||
|
||||
@@ -16,8 +16,8 @@ package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/discord"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/discord"
|
||||
)
|
||||
|
||||
func NewDiscordProvider(token string, channelId string) (*notify.Notify, error) {
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/googlechat"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/googlechat"
|
||||
"google.golang.org/api/chat/v1"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/lark"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/lark"
|
||||
)
|
||||
|
||||
func NewLarkProvider(webhookURL string) (notify.Notifier, error) {
|
||||
|
||||
@@ -16,8 +16,8 @@ package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/line"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/line"
|
||||
)
|
||||
|
||||
func NewLineProvider(channelSecret string, accessToken string, receiver string) (*notify.Notify, error) {
|
||||
|
||||
@@ -16,8 +16,8 @@ package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/matrix"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/matrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/msteams"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/msteams"
|
||||
)
|
||||
|
||||
func NewMicrosoftTeamsProvider(webhookURL string) (notify.Notifier, error) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package notification
|
||||
|
||||
import "github.com/casdoor/notify"
|
||||
import notify "github.com/casdoor/notify2"
|
||||
|
||||
func GetNotificationProvider(typ string, clientId string, clientSecret string, clientId2 string, clientSecret2 string, appId string, receiver string, method string, title string, metaData string, regionId string) (notify.Notifier, error) {
|
||||
if typ == "Telegram" {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/pushbullet"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/pushbullet"
|
||||
)
|
||||
|
||||
func NewPushbulletProvider(apiToken string, deviceNickname string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/pushover"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/pushover"
|
||||
)
|
||||
|
||||
func NewPushoverProvider(appToken string, recipientID string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/reddit"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/reddit"
|
||||
)
|
||||
|
||||
func NewRedditProvider(clientId string, clientSecret string, username string, password string, recipient string) (notify.Notifier, error) {
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/rocketchat"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/rocketchat"
|
||||
)
|
||||
|
||||
func NewRocketChatProvider(clientId string, clientSecret string, endpoint string, channelName string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/slack"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/slack"
|
||||
)
|
||||
|
||||
func NewSlackProvider(apiToken string, channelID string) (*notify.Notify, error) {
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/telegram"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/telegram"
|
||||
api "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
)
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/casdoor/proxy"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/twitter"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/twitter"
|
||||
)
|
||||
|
||||
func NewTwitterProvider(consumerKey string, consumerSecret string, accessToken string, accessTokenSecret string, twitterId string) (*notify.Notify, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/viber"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/viber"
|
||||
)
|
||||
|
||||
func NewViberProvider(senderName string, appKey string, webhookURL string, receiverId string) (notify.Notifier, error) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/notify/service/webpush"
|
||||
notify "github.com/casdoor/notify2"
|
||||
"github.com/casdoor/notify2/service/webpush"
|
||||
)
|
||||
|
||||
func NewWebpushProvider(publicKey string, privateKey string, endpoint string) (*notify.Notify, error) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/notify"
|
||||
notify "github.com/casdoor/notify2"
|
||||
)
|
||||
|
||||
// wecomService encapsulates the WeCom webhook client
|
||||
|
||||
@@ -121,6 +121,7 @@ type Application struct {
|
||||
TokenAttributes []*JwtItem `xorm:"mediumtext" json:"tokenAttributes"`
|
||||
ExpireInHours float64 `json:"expireInHours"`
|
||||
RefreshExpireInHours float64 `json:"refreshExpireInHours"`
|
||||
CookieExpireInHours int64 `json:"cookieExpireInHours"`
|
||||
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
|
||||
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
|
||||
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
|
||||
@@ -365,6 +366,22 @@ func extendApplicationWithSigninMethods(application *Application) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func extendApplicationWithSignupItems(application *Application) (err error) {
|
||||
if len(application.SignupItems) == 0 {
|
||||
application.SignupItems = []*SignupItem{
|
||||
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
|
||||
{Name: "Username", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Display name", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Password", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Confirm password", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Email", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Phone", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
{Name: "Agreement", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getApplication(owner string, name string) (*Application, error) {
|
||||
if owner == "" || name == "" {
|
||||
return nil, nil
|
||||
@@ -728,6 +745,22 @@ func AddApplication(application *Application) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Initialize default values for required fields to prevent UI errors
|
||||
err = extendApplicationWithSignupItems(application)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = extendApplicationWithSigninItems(application)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = extendApplicationWithSigninMethods(application)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, providerItem := range application.Providers {
|
||||
providerItem.Provider = nil
|
||||
}
|
||||
@@ -771,6 +804,9 @@ func (application *Application) IsRedirectUriValid(redirectUri string) bool {
|
||||
}
|
||||
|
||||
for _, targetUri := range application.RedirectUris {
|
||||
if targetUri == "" {
|
||||
continue
|
||||
}
|
||||
targetUriRegex := regexp.MustCompile(targetUri)
|
||||
if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) {
|
||||
return true
|
||||
|
||||
@@ -119,9 +119,9 @@ func CheckUserSignup(application *Application, organization *Organization, authF
|
||||
if authForm.Name == "" {
|
||||
return i18n.Translate(lang, "check:DisplayName cannot be blank")
|
||||
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
||||
if !isValidRealName(authForm.Name) {
|
||||
return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
||||
}
|
||||
// if !isValidRealName(authForm.Name) {
|
||||
// return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,20 @@ func CheckPasswordComplexity(user *User, password string, lang string) string {
|
||||
return CheckPasswordComplexityByOrg(organization, password, lang)
|
||||
}
|
||||
|
||||
func CheckLdapUserPassword(user *User, password string, lang string) error {
|
||||
func CheckLdapUserPassword(user *User, password string, lang string, options ...bool) error {
|
||||
enableCaptcha := false
|
||||
if len(options) > 0 {
|
||||
enableCaptcha = options[0]
|
||||
}
|
||||
|
||||
// check the login error times
|
||||
if !enableCaptcha {
|
||||
err := checkSigninErrorTimes(user, lang)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ldaps, err := GetLdaps(user.Owner)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -340,7 +353,7 @@ func CheckLdapUserPassword(user *User, password string, lang string) error {
|
||||
if !hit {
|
||||
return fmt.Errorf("user not exist")
|
||||
}
|
||||
return fmt.Errorf(i18n.Translate(lang, "check:LDAP user name or password incorrect"))
|
||||
return recordSigninErrorInfo(user, lang, enableCaptcha)
|
||||
}
|
||||
return resetUserSigninErrorTimes(user)
|
||||
}
|
||||
@@ -383,22 +396,14 @@ func CheckUserPassword(organization string, username string, password string, la
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:password or code is incorrect"))
|
||||
}
|
||||
|
||||
// check the login error times
|
||||
if !enableCaptcha {
|
||||
err = checkSigninErrorTimes(user, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// only for LDAP users
|
||||
err = CheckLdapUserPassword(user, password, lang)
|
||||
err = CheckLdapUserPassword(user, password, lang, enableCaptcha)
|
||||
if err != nil {
|
||||
if err.Error() == "user not exist" {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username)
|
||||
}
|
||||
|
||||
return nil, recordSigninErrorInfo(user, lang, enableCaptcha)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
err = CheckPassword(user, password, lang, enableCaptcha)
|
||||
|
||||
@@ -63,6 +63,10 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID card type", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID card", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Real name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID verification", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
@@ -101,7 +105,7 @@ func initBuiltInOrganization() bool {
|
||||
DisplayName: "Built-in Organization",
|
||||
WebsiteUrl: "https://example.com",
|
||||
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
|
||||
PasswordType: "plain",
|
||||
PasswordType: "bcrypt",
|
||||
PasswordOptions: []string{"AtLeast6"},
|
||||
CountryCodes: []string{"US", "ES", "FR", "DE", "GB", "CN", "JP", "KR", "VN", "ID", "SG", "IN"},
|
||||
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||
@@ -210,6 +214,8 @@ func initBuiltInApplication() {
|
||||
TokenFields: []string{},
|
||||
ExpireInHours: 168,
|
||||
FormOffset: 2,
|
||||
|
||||
CookieExpireInHours: 720,
|
||||
}
|
||||
_, err = AddApplication(application)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/logs"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type MfaProps struct {
|
||||
}
|
||||
|
||||
type MfaInterface interface {
|
||||
Initiate(userId string) (*MfaProps, error)
|
||||
Initiate(userId string, issuer string) (*MfaProps, error)
|
||||
SetupVerify(passcode string) error
|
||||
Enable(user *User) error
|
||||
Verify(passcode string) error
|
||||
|
||||
@@ -31,7 +31,7 @@ type PushMfa struct {
|
||||
challengeExp time.Time
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *PushMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ type RadiusMfa struct {
|
||||
provider *Provider
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *RadiusMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestRadiusMfaUtil(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test Initiate
|
||||
mfaProps, err := radiusMfa.Initiate("test/user")
|
||||
mfaProps, err := radiusMfa.Initiate("test/user", "")
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type SmsMfa struct {
|
||||
*MfaProps
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *SmsMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -33,12 +33,11 @@ type TotpMfa struct {
|
||||
digits otp.Digits
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
//issuer := beego.AppConfig.String("appname")
|
||||
//if issuer == "" {
|
||||
// issuer = "casdoor"
|
||||
//}
|
||||
issuer := "Casdoor"
|
||||
func (mfa *TotpMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
// Use the provided issuer (application display name), or fall back to "Casdoor" if not provided
|
||||
if issuer == "" {
|
||||
issuer = "Casdoor"
|
||||
}
|
||||
|
||||
key, err := totp.Generate(totp.GenerateOpts{
|
||||
Issuer: issuer,
|
||||
|
||||
115
object/mfa_totp_test.go
Normal file
115
object/mfa_totp_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2025 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"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTotpMfaUtil(t *testing.T) {
|
||||
// Test creating a new TOTP MFA util
|
||||
config := &MfaProps{
|
||||
MfaType: TotpType,
|
||||
}
|
||||
|
||||
totpMfa := NewTotpMfaUtil(config)
|
||||
if totpMfa == nil {
|
||||
t.Error("NewTotpMfaUtil returned nil")
|
||||
return
|
||||
}
|
||||
|
||||
if totpMfa.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, totpMfa.MfaType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotpMfaInitiate_WithCustomIssuer(t *testing.T) {
|
||||
totpMfa := NewTotpMfaUtil(nil)
|
||||
// Test with custom issuer (application display name)
|
||||
customIssuer := "My Application"
|
||||
mfaProps, err := totpMfa.Initiate("test/user", customIssuer)
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
if mfaProps == nil {
|
||||
t.Error("Initiate returned nil mfaProps")
|
||||
return
|
||||
}
|
||||
|
||||
if mfaProps.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, mfaProps.MfaType)
|
||||
}
|
||||
|
||||
if mfaProps.Secret == "" {
|
||||
t.Error("Secret should not be empty")
|
||||
}
|
||||
|
||||
if mfaProps.URL == "" {
|
||||
t.Error("URL should not be empty")
|
||||
}
|
||||
|
||||
// Verify the URL contains the custom issuer (URL-encoded or plain)
|
||||
if !strings.Contains(mfaProps.URL, customIssuer) && !strings.Contains(mfaProps.URL, "My%20Application") {
|
||||
t.Errorf("URL should contain custom issuer '%s', got: %s", customIssuer, mfaProps.URL)
|
||||
}
|
||||
|
||||
// Verify the URL contains the user ID
|
||||
if !strings.Contains(mfaProps.URL, "test/user") {
|
||||
t.Errorf("URL should contain user ID 'test/user', got: %s", mfaProps.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotpMfaInitiate_WithEmptyIssuer(t *testing.T) {
|
||||
totpMfa := NewTotpMfaUtil(nil)
|
||||
// Test with empty issuer (should default to "Casdoor")
|
||||
mfaProps, err := totpMfa.Initiate("test/user", "")
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
if mfaProps == nil {
|
||||
t.Error("Initiate returned nil mfaProps")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the URL contains the default issuer "Casdoor"
|
||||
if !strings.Contains(mfaProps.URL, "Casdoor") {
|
||||
t.Errorf("URL should contain default issuer 'Casdoor', got: %s", mfaProps.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMfaUtil_Totp(t *testing.T) {
|
||||
config := &MfaProps{
|
||||
MfaType: TotpType,
|
||||
Secret: "testsecret",
|
||||
}
|
||||
|
||||
mfaUtil := GetMfaUtil(TotpType, config)
|
||||
if mfaUtil == nil {
|
||||
t.Error("GetMfaUtil returned nil for TOTP type")
|
||||
return
|
||||
}
|
||||
|
||||
totpMfa, ok := mfaUtil.(*TotpMfa)
|
||||
if !ok {
|
||||
t.Error("GetMfaUtil did not return TotpMfa type")
|
||||
}
|
||||
|
||||
if totpMfa.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, totpMfa.MfaType)
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,12 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/notification"
|
||||
"github.com/casdoor/notify"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
notify "github.com/casdoor/notify2"
|
||||
)
|
||||
|
||||
func getNotificationClient(provider *Provider) (notify.Notifier, error) {
|
||||
@@ -43,9 +46,55 @@ func SendNotification(provider *Provider, content string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// SsoLogoutNotification represents the structure of a session-level SSO logout notification
|
||||
// This includes session information and a signature for authentication
|
||||
type SsoLogoutNotification struct {
|
||||
// User information
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Id string `json:"id"`
|
||||
|
||||
// Event type
|
||||
Event string `json:"event"`
|
||||
|
||||
// Session-level information for targeted logout
|
||||
SessionIds []string `json:"sessionIds"` // List of session IDs being logged out
|
||||
AccessTokenHashes []string `json:"accessTokenHashes"` // Hashes of access tokens being expired
|
||||
|
||||
// Authentication fields to prevent malicious logout requests
|
||||
Nonce string `json:"nonce"` // Random nonce for replay protection
|
||||
Timestamp int64 `json:"timestamp"` // Unix timestamp of the notification
|
||||
Signature string `json:"signature"` // HMAC-SHA256 signature for verification
|
||||
}
|
||||
|
||||
// GetTokensByUser retrieves all tokens for a specific user
|
||||
func GetTokensByUser(owner, username string) ([]*Token, error) {
|
||||
tokens := []*Token{}
|
||||
err := ormer.Engine.Where("organization = ? and user = ?", owner, username).Find(&tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
// generateLogoutSignature generates an HMAC-SHA256 signature for the logout notification
|
||||
// The signature is computed over the critical fields to prevent tampering
|
||||
func generateLogoutSignature(clientSecret string, owner string, name string, nonce string, timestamp int64, sessionIds []string, accessTokenHashes []string) string {
|
||||
// Create a deterministic string from all fields that need to be verified
|
||||
// Use strings.Join to avoid trailing separators and improve performance
|
||||
sessionIdsStr := strings.Join(sessionIds, ",")
|
||||
tokenHashesStr := strings.Join(accessTokenHashes, ",")
|
||||
|
||||
data := fmt.Sprintf("%s|%s|%s|%d|%s|%s", owner, name, nonce, timestamp, sessionIdsStr, tokenHashesStr)
|
||||
return util.GetHmacSha256(clientSecret, data)
|
||||
}
|
||||
|
||||
// SendSsoLogoutNotifications sends logout notifications to all notification providers
|
||||
// configured in the user's signup application
|
||||
func SendSsoLogoutNotifications(user *User) error {
|
||||
func SendSsoLogoutNotifications(user *User, sessionIds []string, tokens []*Token) error {
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -56,7 +105,7 @@ func SendSsoLogoutNotifications(user *User) error {
|
||||
}
|
||||
|
||||
// Get the user's signup application
|
||||
application, err := GetApplication(user.SignupApplication)
|
||||
application, err := GetApplicationByUser(user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signup application: %w", err)
|
||||
}
|
||||
@@ -65,22 +114,50 @@ func SendSsoLogoutNotifications(user *User) error {
|
||||
return fmt.Errorf("signup application not found: %s", user.SignupApplication)
|
||||
}
|
||||
|
||||
// Prepare sanitized user data for notification
|
||||
// Only include safe, non-sensitive fields
|
||||
sanitizedData := map[string]interface{}{
|
||||
"owner": user.Owner,
|
||||
"name": user.Name,
|
||||
"displayName": user.DisplayName,
|
||||
"email": user.Email,
|
||||
"phone": user.Phone,
|
||||
"id": user.Id,
|
||||
"event": "sso-logout",
|
||||
// Extract access token hashes from tokens
|
||||
accessTokenHashes := make([]string, 0, len(tokens))
|
||||
for _, token := range tokens {
|
||||
if token.AccessTokenHash != "" {
|
||||
accessTokenHashes = append(accessTokenHashes, token.AccessTokenHash)
|
||||
}
|
||||
}
|
||||
userData, err := json.Marshal(sanitizedData)
|
||||
|
||||
// Generate nonce and timestamp for replay protection
|
||||
nonce := util.GenerateId()
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
// Generate signature using the application's client secret
|
||||
signature := generateLogoutSignature(
|
||||
application.ClientSecret,
|
||||
user.Owner,
|
||||
user.Name,
|
||||
nonce,
|
||||
timestamp,
|
||||
sessionIds,
|
||||
accessTokenHashes,
|
||||
)
|
||||
|
||||
// Prepare the notification data
|
||||
notificationObj := SsoLogoutNotification{
|
||||
Owner: user.Owner,
|
||||
Name: user.Name,
|
||||
DisplayName: user.DisplayName,
|
||||
Email: user.Email,
|
||||
Phone: user.Phone,
|
||||
Id: user.Id,
|
||||
Event: "sso-logout",
|
||||
SessionIds: sessionIds,
|
||||
AccessTokenHashes: accessTokenHashes,
|
||||
Nonce: nonce,
|
||||
Timestamp: timestamp,
|
||||
Signature: signature,
|
||||
}
|
||||
|
||||
notificationData, err := json.Marshal(notificationObj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal user data: %w", err)
|
||||
}
|
||||
content := string(userData)
|
||||
content := string(notificationData)
|
||||
|
||||
// Send notifications to all notification providers in the signup application
|
||||
for _, providerItem := range application.Providers {
|
||||
@@ -102,3 +179,18 @@ func SendSsoLogoutNotifications(user *User) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifySsoLogoutSignature verifies the signature of an SSO logout notification
|
||||
// This should be called by applications receiving logout notifications
|
||||
func VerifySsoLogoutSignature(clientSecret string, notification *SsoLogoutNotification) bool {
|
||||
expectedSignature := generateLogoutSignature(
|
||||
clientSecret,
|
||||
notification.Owner,
|
||||
notification.Name,
|
||||
notification.Nonce,
|
||||
notification.Timestamp,
|
||||
notification.SessionIds,
|
||||
notification.AccessTokenHashes,
|
||||
)
|
||||
return notification.Signature == expectedSignature
|
||||
}
|
||||
|
||||
154
object/notification_test.go
Normal file
154
object/notification_test.go
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright 2024 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 (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateLogoutSignature(t *testing.T) {
|
||||
// Test that the signature generation is deterministic
|
||||
clientSecret := "test-secret-key"
|
||||
owner := "test-org"
|
||||
name := "test-user"
|
||||
nonce := "test-nonce-123"
|
||||
timestamp := int64(1699900000)
|
||||
sessionIds := []string{"session-1", "session-2"}
|
||||
accessTokenHashes := []string{"hash-1", "hash-2"}
|
||||
|
||||
sig1 := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, sessionIds, accessTokenHashes)
|
||||
sig2 := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, sessionIds, accessTokenHashes)
|
||||
|
||||
if sig1 != sig2 {
|
||||
t.Errorf("Signature should be deterministic, got %s and %s", sig1, sig2)
|
||||
}
|
||||
|
||||
// Test that different inputs produce different signatures
|
||||
sig3 := generateLogoutSignature(clientSecret, owner, "different-user", nonce, timestamp, sessionIds, accessTokenHashes)
|
||||
if sig1 == sig3 {
|
||||
t.Error("Different inputs should produce different signatures")
|
||||
}
|
||||
|
||||
// Test with different client secret
|
||||
sig4 := generateLogoutSignature("different-secret", owner, name, nonce, timestamp, sessionIds, accessTokenHashes)
|
||||
if sig1 == sig4 {
|
||||
t.Error("Different client secrets should produce different signatures")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifySsoLogoutSignature(t *testing.T) {
|
||||
clientSecret := "test-secret-key"
|
||||
owner := "test-org"
|
||||
name := "test-user"
|
||||
nonce := "test-nonce-123"
|
||||
timestamp := int64(1699900000)
|
||||
sessionIds := []string{"session-1", "session-2"}
|
||||
accessTokenHashes := []string{"hash-1", "hash-2"}
|
||||
|
||||
// Generate a valid signature
|
||||
signature := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, sessionIds, accessTokenHashes)
|
||||
|
||||
// Create a notification with the valid signature
|
||||
notification := &SsoLogoutNotification{
|
||||
Owner: owner,
|
||||
Name: name,
|
||||
Nonce: nonce,
|
||||
Timestamp: timestamp,
|
||||
SessionIds: sessionIds,
|
||||
AccessTokenHashes: accessTokenHashes,
|
||||
Signature: signature,
|
||||
}
|
||||
|
||||
// Verify with correct secret
|
||||
if !VerifySsoLogoutSignature(clientSecret, notification) {
|
||||
t.Error("Valid signature should be verified successfully")
|
||||
}
|
||||
|
||||
// Verify with wrong secret
|
||||
if VerifySsoLogoutSignature("wrong-secret", notification) {
|
||||
t.Error("Invalid signature should not be verified")
|
||||
}
|
||||
|
||||
// Verify with tampered data
|
||||
tamperedNotification := &SsoLogoutNotification{
|
||||
Owner: owner,
|
||||
Name: "tampered-user", // Changed
|
||||
Nonce: nonce,
|
||||
Timestamp: timestamp,
|
||||
SessionIds: sessionIds,
|
||||
AccessTokenHashes: accessTokenHashes,
|
||||
Signature: signature, // Same signature
|
||||
}
|
||||
if VerifySsoLogoutSignature(clientSecret, tamperedNotification) {
|
||||
t.Error("Tampered notification should not be verified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSsoLogoutNotificationStructure(t *testing.T) {
|
||||
notification := SsoLogoutNotification{
|
||||
Owner: "test-org",
|
||||
Name: "test-user",
|
||||
DisplayName: "Test User",
|
||||
Email: "test@example.com",
|
||||
Phone: "+1234567890",
|
||||
Id: "user-123",
|
||||
Event: "sso-logout",
|
||||
SessionIds: []string{"session-1", "session-2"},
|
||||
AccessTokenHashes: []string{"hash-1", "hash-2"},
|
||||
Nonce: "nonce-123",
|
||||
Timestamp: 1699900000,
|
||||
Signature: "sig-123",
|
||||
}
|
||||
|
||||
// Verify all fields are set correctly
|
||||
if notification.Owner != "test-org" {
|
||||
t.Errorf("Owner mismatch, got %s", notification.Owner)
|
||||
}
|
||||
if notification.Name != "test-user" {
|
||||
t.Errorf("Name mismatch, got %s", notification.Name)
|
||||
}
|
||||
if notification.Event != "sso-logout" {
|
||||
t.Errorf("Event mismatch, got %s", notification.Event)
|
||||
}
|
||||
if len(notification.SessionIds) != 2 {
|
||||
t.Errorf("SessionIds count mismatch, got %d", len(notification.SessionIds))
|
||||
}
|
||||
if len(notification.AccessTokenHashes) != 2 {
|
||||
t.Errorf("AccessTokenHashes count mismatch, got %d", len(notification.AccessTokenHashes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateLogoutSignatureWithEmptyArrays(t *testing.T) {
|
||||
clientSecret := "test-secret-key"
|
||||
owner := "test-org"
|
||||
name := "test-user"
|
||||
nonce := "test-nonce-123"
|
||||
timestamp := int64(1699900000)
|
||||
|
||||
// Test with empty session IDs and token hashes
|
||||
sig1 := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, []string{}, []string{})
|
||||
sig2 := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, nil, nil)
|
||||
|
||||
// Empty slice and nil should produce the same signature
|
||||
if sig1 != sig2 {
|
||||
t.Errorf("Empty slice and nil should produce the same signature, got %s and %s", sig1, sig2)
|
||||
}
|
||||
|
||||
// Should be different from non-empty arrays
|
||||
sig3 := generateLogoutSignature(clientSecret, owner, name, nonce, timestamp, []string{"session-1"}, []string{"hash-1"})
|
||||
if sig1 == sig3 {
|
||||
t.Error("Empty arrays should produce different signature from non-empty arrays")
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
)
|
||||
|
||||
type OidcDiscovery struct {
|
||||
@@ -140,7 +140,7 @@ func GetOidcDiscovery(host string, applicationName string) OidcDiscovery {
|
||||
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
|
||||
ResponseTypesSupported: []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"},
|
||||
ResponseModesSupported: []string{"query", "fragment", "form_post"},
|
||||
GrantTypesSupported: []string{"password", "authorization_code"},
|
||||
GrantTypesSupported: []string{"authorization_code", "implicit", "password", "client_credentials", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code"},
|
||||
SubjectTypesSupported: []string{"public"},
|
||||
IdTokenSigningAlgValuesSupported: []string{"RS256", "RS512", "ES256", "ES384", "ES512"},
|
||||
ScopesSupported: []string{"openid", "email", "profile", "address", "phone", "offline_access"},
|
||||
|
||||
@@ -92,7 +92,7 @@ func PlaceOrder(productId string, user *User, pricingName string, planName strin
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func PayOrder(providerName, host, paymentEnv string, order *Order) (payment *Payment, attachInfo map[string]interface{}, err error) {
|
||||
func PayOrder(providerName, host, paymentEnv string, order *Order, lang string) (payment *Payment, attachInfo map[string]interface{}, err error) {
|
||||
if order.State != "Created" {
|
||||
return nil, nil, fmt.Errorf("cannot pay for order: %s, current state is %s", order.GetId(), order.State)
|
||||
}
|
||||
@@ -210,7 +210,6 @@ func PayOrder(providerName, host, paymentEnv string, order *Order) (payment *Pay
|
||||
ProductName: product.Name,
|
||||
ProductDisplayName: product.DisplayName,
|
||||
Detail: product.Detail,
|
||||
Tag: product.Tag,
|
||||
Currency: order.Currency,
|
||||
Price: order.Price,
|
||||
IsRecharge: product.IsRecharge,
|
||||
@@ -223,58 +222,8 @@ func PayOrder(providerName, host, paymentEnv string, order *Order) (payment *Pay
|
||||
OutOrderId: payResp.OrderId,
|
||||
}
|
||||
|
||||
transaction := &Transaction{
|
||||
Owner: payment.Owner,
|
||||
Name: payment.Name,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
DisplayName: payment.DisplayName,
|
||||
Application: owner,
|
||||
Domain: "",
|
||||
Amount: payment.Price,
|
||||
Currency: order.Currency,
|
||||
Payment: payment.Name,
|
||||
State: pp.PaymentStateCreated,
|
||||
}
|
||||
|
||||
if product.IsRecharge {
|
||||
transaction.Category = "Recharge"
|
||||
transaction.Type = ""
|
||||
transaction.Subtype = ""
|
||||
transaction.Provider = ""
|
||||
transaction.Tag = "User"
|
||||
transaction.User = payment.User
|
||||
transaction.State = pp.PaymentStatePaid
|
||||
} else {
|
||||
transaction.Category = ""
|
||||
transaction.Type = provider.Category
|
||||
transaction.Subtype = provider.Type
|
||||
transaction.Provider = provider.Name
|
||||
transaction.Tag = product.Tag
|
||||
transaction.User = payment.User
|
||||
}
|
||||
|
||||
if provider.Type == "Dummy" {
|
||||
if provider.Type == "Dummy" || provider.Type == "Balance" {
|
||||
payment.State = pp.PaymentStatePaid
|
||||
currency := payment.Currency
|
||||
if currency == "" {
|
||||
currency = "USD"
|
||||
}
|
||||
err = UpdateUserBalance(user.Owner, user.Name, payment.Price, currency, "en")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else if provider.Type == "Balance" {
|
||||
convertedPrice := ConvertCurrency(order.Price, order.Currency, user.BalanceCurrency)
|
||||
if convertedPrice > user.Balance {
|
||||
return nil, nil, fmt.Errorf("insufficient user balance")
|
||||
}
|
||||
transaction.Amount = -transaction.Amount
|
||||
err = UpdateUserBalance(user.Owner, user.Name, -convertedPrice, user.BalanceCurrency, "en")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
payment.State = pp.PaymentStatePaid
|
||||
transaction.State = pp.PaymentStatePaid
|
||||
}
|
||||
|
||||
affected, err := AddPayment(payment)
|
||||
@@ -286,14 +235,56 @@ func PayOrder(providerName, host, paymentEnv string, order *Order) (payment *Pay
|
||||
return nil, nil, fmt.Errorf("failed to add payment: %s", util.StructToJson(payment))
|
||||
}
|
||||
|
||||
if product.IsRecharge || provider.Type == "Balance" {
|
||||
affected, _, err = AddTransaction(transaction, "en", false)
|
||||
if provider.Type == "Balance" {
|
||||
transaction := &Transaction{
|
||||
Owner: payment.Owner,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: user.SignupApplication,
|
||||
Amount: -payment.Price,
|
||||
Currency: order.Currency,
|
||||
Payment: payment.Name,
|
||||
Category: TransactionCategoryPurchase,
|
||||
Type: provider.Category,
|
||||
Subtype: provider.Type,
|
||||
Provider: provider.Name,
|
||||
Tag: "User",
|
||||
User: payment.User,
|
||||
State: string(pp.PaymentStatePaid),
|
||||
}
|
||||
|
||||
affected, err = AddInternalPaymentTransaction(transaction, lang)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !affected {
|
||||
return nil, nil, fmt.Errorf("failed to add transaction: %s", util.StructToJson(transaction))
|
||||
}
|
||||
|
||||
if product.IsRecharge {
|
||||
rechargeTransaction := &Transaction{
|
||||
Owner: payment.Owner,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: user.SignupApplication,
|
||||
Amount: payment.Price,
|
||||
Currency: order.Currency,
|
||||
Payment: payment.Name,
|
||||
Category: TransactionCategoryRecharge,
|
||||
Type: provider.Category,
|
||||
Subtype: provider.Type,
|
||||
Provider: provider.Name,
|
||||
Tag: "User",
|
||||
User: payment.User,
|
||||
State: string(pp.PaymentStatePaid),
|
||||
}
|
||||
|
||||
affected, err = AddInternalPaymentTransaction(rechargeTransaction, lang)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !affected {
|
||||
return nil, nil, fmt.Errorf("failed to add recharge transaction: %s", util.StructToJson(rechargeTransaction))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
order.Payment = payment.Name
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user