mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-17 04:44:45 +08:00
Compare commits
72 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
de2932b5fb | ||
![]() |
f4c873ffe6 | ||
![]() |
97c7f2631a | ||
![]() |
93f0425759 | ||
![]() |
6a00657e42 | ||
![]() |
88130bf020 | ||
![]() |
5e99007fc9 | ||
![]() |
66aca3124c | ||
![]() |
61deb75c84 | ||
![]() |
b8db07db4d | ||
![]() |
a681c267b3 | ||
![]() |
5fb6ea0ab4 | ||
![]() |
0f6b7984d4 | ||
![]() |
ba9d6e5d78 | ||
![]() |
a4524e9996 | ||
![]() |
b469928780 | ||
![]() |
dc6fe13f75 | ||
![]() |
8227762988 | ||
![]() |
d92b072ed0 | ||
![]() |
1161310f81 | ||
![]() |
48ba5f91ed | ||
![]() |
53df2c2704 | ||
![]() |
78066da208 | ||
![]() |
60096468fe | ||
![]() |
39d6bc10f7 | ||
![]() |
177f2f2f11 | ||
![]() |
79b393afee | ||
![]() |
5bb12a30d4 | ||
![]() |
fdb68bf9c8 | ||
![]() |
37748850c8 | ||
![]() |
8968396ae5 | ||
![]() |
f5395f15f9 | ||
![]() |
73e44df867 | ||
![]() |
0b575ccf84 | ||
![]() |
9b7f465a47 | ||
![]() |
b1fe28fb83 | ||
![]() |
530d054adb | ||
![]() |
a2b9f9baaf | ||
![]() |
a2d20fcb63 | ||
![]() |
b118a3bb76 | ||
![]() |
280867d0cb | ||
![]() |
30fa2f7d81 | ||
![]() |
518288691d | ||
![]() |
ffa54247cd | ||
![]() |
0199ad9aaa | ||
![]() |
b9d171718f | ||
![]() |
e841d0ba8e | ||
![]() |
e5a9594f90 | ||
![]() |
c542929835 | ||
![]() |
86dea71efd | ||
![]() |
9e536850fd | ||
![]() |
fddd4a12b8 | ||
![]() |
2d6fae32be | ||
![]() |
741cff99df | ||
![]() |
cad9c28e92 | ||
![]() |
524cf4dda5 | ||
![]() |
077a1cb8b7 | ||
![]() |
00efdf1d03 | ||
![]() |
aa543f1abb | ||
![]() |
1d1d3049bd | ||
![]() |
4f497d44a5 | ||
![]() |
369de36987 | ||
![]() |
e3f28e8b4c | ||
![]() |
3373174c65 | ||
![]() |
2fb79e4092 | ||
![]() |
5846e337c7 | ||
![]() |
44f4de1440 | ||
![]() |
27adeb4620 | ||
![]() |
5c107db43b | ||
![]() |
27187b3a54 | ||
![]() |
14fcedcc5d | ||
![]() |
e7c015f288 |
34
.github/workflows/build.yml
vendored
34
.github/workflows/build.yml
vendored
@@ -1,6 +1,6 @@
|
|||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [ push, pull_request ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@@ -167,10 +167,8 @@ jobs:
|
|||||||
elif [ ${old_array[1]} != ${new_array[1]} ]
|
elif [ ${old_array[1]} != ${new_array[1]} ]
|
||||||
then
|
then
|
||||||
echo ::set-output name=push::'true'
|
echo ::set-output name=push::'true'
|
||||||
|
|
||||||
else
|
else
|
||||||
echo ::set-output name=push::'false'
|
echo ::set-output name=push::'false'
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
@@ -208,3 +206,33 @@ jobs:
|
|||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
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:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
if: steps.should_push.outputs.push=='true'
|
||||||
|
with:
|
||||||
|
repository: casdoor/casdoor-helm
|
||||||
|
ref: 'master'
|
||||||
|
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Update Helm Chart
|
||||||
|
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
|
||||||
|
|
||||||
|
REGISTRY=oci://registry-1.docker.io/casbin
|
||||||
|
cd charts/casdoor
|
||||||
|
helm package .
|
||||||
|
PKG_NAME=$(ls *.tgz)
|
||||||
|
helm repo index . --url $REGISTRY --merge index.yaml
|
||||||
|
helm push $PKG_NAME $REGISTRY
|
||||||
|
rm $PKG_NAME
|
||||||
|
|
||||||
|
# Commit and push the changes back to the repository
|
||||||
|
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 push origin HEAD:master --follow-tags
|
||||||
|
40
.github/workflows/helm.yml
vendored
40
.github/workflows/helm.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: Helm Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- 'manifests/casdoor/Chart.yaml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release-helm-chart:
|
|
||||||
name: Release Helm Chart
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up Helm
|
|
||||||
uses: azure/setup-helm@v3
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Release Helm Chart
|
|
||||||
run: |
|
|
||||||
cd manifests/casdoor
|
|
||||||
REGISTRY=oci://registry-1.docker.io/casbin
|
|
||||||
helm package .
|
|
||||||
PKG_NAME=$(ls *.tgz)
|
|
||||||
helm repo index . --url $REGISTRY --merge index.yaml
|
|
||||||
helm push $PKG_NAME $REGISTRY
|
|
||||||
rm $PKG_NAME
|
|
||||||
|
|
||||||
- name: Commit updated helm index.yaml
|
|
||||||
uses: stefanzweifel/git-auto-commit-action@v5
|
|
||||||
with:
|
|
||||||
commit_message: 'ci: update helm index.yaml'
|
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -18,7 +18,7 @@ bin/
|
|||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
.vscode/
|
.vscode/settings.json
|
||||||
|
|
||||||
tmp/
|
tmp/
|
||||||
tmpFiles/
|
tmpFiles/
|
||||||
@@ -31,3 +31,6 @@ commentsRouter*.go
|
|||||||
# ignore build result
|
# ignore build result
|
||||||
casdoor
|
casdoor
|
||||||
server
|
server
|
||||||
|
|
||||||
|
# include helm-chart
|
||||||
|
!manifests/casdoor
|
||||||
|
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"debugAdapter": "dlv-dap",
|
||||||
|
"args": ["--createDatabase=true"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
3
Makefile
3
Makefile
@@ -86,6 +86,9 @@ docker-build: ## Build docker image with the manager.
|
|||||||
docker-push: ## Push docker image with the manager.
|
docker-push: ## Push docker image with the manager.
|
||||||
docker push ${REGISTRY}/${IMG}:${IMG_TAG}
|
docker push ${REGISTRY}/${IMG}:${IMG_TAG}
|
||||||
|
|
||||||
|
deps: ## Run dependencies for local development
|
||||||
|
docker compose up -d db
|
||||||
|
|
||||||
lint-install: ## Install golangci-lint
|
lint-install: ## Install golangci-lint
|
||||||
@# The following installs a specific version of golangci-lint, which is appropriate for a CI server to avoid different results from build to build
|
@# The following installs a specific version of golangci-lint, which is appropriate for a CI server to avoid different results from build to build
|
||||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.40.1
|
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.40.1
|
||||||
|
@@ -69,6 +69,7 @@ https://casdoor.org
|
|||||||
|
|
||||||
- By source code: https://casdoor.org/docs/basic/server-installation
|
- By source code: https://casdoor.org/docs/basic/server-installation
|
||||||
- By Docker: https://casdoor.org/docs/basic/try-with-docker
|
- By Docker: https://casdoor.org/docs/basic/try-with-docker
|
||||||
|
- By Kubernetes Helm: https://casdoor.org/docs/basic/try-with-helm
|
||||||
|
|
||||||
## How to connect to Casdoor?
|
## How to connect to Casdoor?
|
||||||
|
|
||||||
|
@@ -150,7 +150,7 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
|||||||
|
|
||||||
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") {
|
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") {
|
||||||
return true
|
return true
|
||||||
} else if urlPath == "/api/update-user" {
|
} else if urlPath == "/api/update-user" {
|
||||||
// Allow ordinary users to update their own information
|
// Allow ordinary users to update their own information
|
||||||
|
@@ -56,6 +56,17 @@ type Captcha struct {
|
|||||||
SubType string `json:"subType"`
|
SubType string `json:"subType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this API is used by "Api URL" of Flarum's FoF Passport plugin
|
||||||
|
// https://github.com/FriendsOfFlarum/passport
|
||||||
|
type LaravelResponse struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
EmailVerifiedAt string `json:"email_verified_at"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
// Signup
|
// Signup
|
||||||
// @Tag Login API
|
// @Tag Login API
|
||||||
// @Title Signup
|
// @Title Signup
|
||||||
@@ -418,7 +429,7 @@ func (c *ApiController) GetUserinfo() {
|
|||||||
// @Title UserInfo2
|
// @Title UserInfo2
|
||||||
// @Tag Account API
|
// @Tag Account API
|
||||||
// @Description return Laravel compatible user information according to OAuth 2.0
|
// @Description return Laravel compatible user information according to OAuth 2.0
|
||||||
// @Success 200 {object} LaravelResponse The Response object
|
// @Success 200 {object} controllers.LaravelResponse The Response object
|
||||||
// @router /user [get]
|
// @router /user [get]
|
||||||
func (c *ApiController) GetUserinfo2() {
|
func (c *ApiController) GetUserinfo2() {
|
||||||
user, ok := c.RequireSignedInUser()
|
user, ok := c.RequireSignedInUser()
|
||||||
@@ -426,17 +437,6 @@ func (c *ApiController) GetUserinfo2() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// this API is used by "Api URL" of Flarum's FoF Passport plugin
|
|
||||||
// https://github.com/FriendsOfFlarum/passport
|
|
||||||
type LaravelResponse struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
EmailVerifiedAt string `json:"email_verified_at"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
response := LaravelResponse{
|
response := LaravelResponse{
|
||||||
Id: user.Id,
|
Id: user.Id,
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
@@ -453,7 +453,7 @@ func (c *ApiController) GetUserinfo2() {
|
|||||||
// GetCaptcha ...
|
// GetCaptcha ...
|
||||||
// @Tag Login API
|
// @Tag Login API
|
||||||
// @Title GetCaptcha
|
// @Title GetCaptcha
|
||||||
// @router /api/get-captcha [get]
|
// @router /get-captcha [get]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) GetCaptcha() {
|
func (c *ApiController) GetCaptcha() {
|
||||||
applicationId := c.Input().Get("applicationId")
|
applicationId := c.Input().Get("applicationId")
|
||||||
|
@@ -110,14 +110,6 @@ func (c *ApiController) GetApplication() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 as an initialization value, corresponding to the default configuration parameters
|
|
||||||
if application.FailedSigninLimit == 0 {
|
|
||||||
application.FailedSigninLimit = object.DefaultFailedSigninLimit
|
|
||||||
}
|
|
||||||
if application.FailedSigninfrozenTime == 0 {
|
|
||||||
application.FailedSigninfrozenTime = object.DefaultFailedSigninfrozenTime
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(object.GetMaskedApplication(application, userId))
|
c.ResponseOk(object.GetMaskedApplication(application, userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -222,7 +222,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
// @Param redirectUri query string true "redirect uri"
|
// @Param redirectUri query string true "redirect uri"
|
||||||
// @Param scope query string true "scope"
|
// @Param scope query string true "scope"
|
||||||
// @Param state query string true "state"
|
// @Param state query string true "state"
|
||||||
// @Success 200 {object} Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /get-app-login [get]
|
// @router /get-app-login [get]
|
||||||
func (c *ApiController) GetApplicationLogin() {
|
func (c *ApiController) GetApplicationLogin() {
|
||||||
clientId := c.Input().Get("clientId")
|
clientId := c.Input().Get("clientId")
|
||||||
@@ -342,7 +342,28 @@ func (c *ApiController) Login() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var application *object.Application
|
||||||
|
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error(), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if application == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
verificationCodeType := object.GetVerifyType(authForm.Username)
|
verificationCodeType := object.GetVerifyType(authForm.Username)
|
||||||
|
if verificationCodeType == object.VerifyTypeEmail && !application.IsCodeSigninViaEmailEnabled() {
|
||||||
|
c.ResponseError(c.T("auth:The login method: login with email is not enabled for the application"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if verificationCodeType == object.VerifyTypePhone && !application.IsCodeSigninViaSmsEnabled() {
|
||||||
|
c.ResponseError(c.T("auth:The login method: login with SMS is not enabled for the application"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var checkDest string
|
var checkDest string
|
||||||
if verificationCodeType == object.VerifyTypePhone {
|
if verificationCodeType == object.VerifyTypePhone {
|
||||||
authForm.CountryCode = user.GetCountryCode(authForm.CountryCode)
|
authForm.CountryCode = user.GetCountryCode(authForm.CountryCode)
|
||||||
@@ -378,10 +399,14 @@ func (c *ApiController) Login() {
|
|||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !application.EnablePassword {
|
if authForm.SigninMethod == "Password" && !application.IsPasswordEnabled() {
|
||||||
c.ResponseError(c.T("auth:The login method: login with password is not enabled for the application"))
|
c.ResponseError(c.T("auth:The login method: login with password is not enabled for the application"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if authForm.SigninMethod == "LDAP" && !application.IsLdapEnabled() {
|
||||||
|
c.ResponseError(c.T("auth:The login method: login with LDAP is not enabled for the application"))
|
||||||
|
return
|
||||||
|
}
|
||||||
var enableCaptcha bool
|
var enableCaptcha bool
|
||||||
if enableCaptcha, err = object.CheckToEnableCaptcha(application, authForm.Organization, authForm.Username); err != nil {
|
if enableCaptcha, err = object.CheckToEnableCaptcha(application, authForm.Organization, authForm.Username); err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
@@ -411,7 +436,14 @@ func (c *ApiController) Login() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
password := authForm.Password
|
password := authForm.Password
|
||||||
user, err = object.CheckUserPassword(authForm.Organization, authForm.Username, password, c.GetAcceptLanguage(), enableCaptcha)
|
isSigninViaLdap := authForm.SigninMethod == "LDAP"
|
||||||
|
var isPasswordWithLdapEnabled bool
|
||||||
|
if authForm.SigninMethod == "Password" {
|
||||||
|
isPasswordWithLdapEnabled = application.IsPasswordWithLdapEnabled()
|
||||||
|
} else {
|
||||||
|
isPasswordWithLdapEnabled = false
|
||||||
|
}
|
||||||
|
user, err = object.CheckUserPassword(authForm.Organization, authForm.Username, password, c.GetAcceptLanguage(), enableCaptcha, isSigninViaLdap, isPasswordWithLdapEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -884,9 +916,9 @@ func (c *ApiController) HandleSamlLogin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleOfficialAccountEvent ...
|
// HandleOfficialAccountEvent ...
|
||||||
// @Tag HandleOfficialAccountEvent API
|
// @Tag System API
|
||||||
// @Title HandleOfficialAccountEvent
|
// @Title HandleOfficialAccountEvent
|
||||||
// @router /api/webhook [POST]
|
// @router /webhook [POST]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) HandleOfficialAccountEvent() {
|
func (c *ApiController) HandleOfficialAccountEvent() {
|
||||||
respBytes, err := ioutil.ReadAll(c.Ctx.Request.Body)
|
respBytes, err := ioutil.ReadAll(c.Ctx.Request.Body)
|
||||||
@@ -915,9 +947,9 @@ func (c *ApiController) HandleOfficialAccountEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookEventType ...
|
// GetWebhookEventType ...
|
||||||
// @Tag GetWebhookEventType API
|
// @Tag System API
|
||||||
// @Title GetWebhookEventType
|
// @Title GetWebhookEventType
|
||||||
// @router /api/get-webhook-event [GET]
|
// @router /get-webhook-event [GET]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) GetWebhookEventType() {
|
func (c *ApiController) GetWebhookEventType() {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
@@ -938,26 +970,30 @@ func (c *ApiController) GetWebhookEventType() {
|
|||||||
// @Description Get Login Error Counts
|
// @Description Get Login Error Counts
|
||||||
// @Param id query string true "The id ( owner/name ) of user"
|
// @Param id query string true "The id ( owner/name ) of user"
|
||||||
// @Success 200 {object} controllers.Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /api/get-captcha-status [get]
|
// @router /get-captcha-status [get]
|
||||||
func (c *ApiController) GetCaptchaStatus() {
|
func (c *ApiController) GetCaptchaStatus() {
|
||||||
organization := c.Input().Get("organization")
|
organization := c.Input().Get("organization")
|
||||||
userId := c.Input().Get("user_id")
|
userId := c.Input().Get("userId")
|
||||||
user, err := object.GetUserByFields(organization, userId)
|
user, err := object.GetUserByFields(organization, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
failedSigninLimit, _, err := object.GetFailedSigninConfigByUser(user)
|
captchaEnabled := false
|
||||||
if err != nil {
|
if user != nil {
|
||||||
c.ResponseError(err.Error())
|
var failedSigninLimit int
|
||||||
return
|
failedSigninLimit, _, err = object.GetFailedSigninConfigByUser(user)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.SigninWrongTimes >= failedSigninLimit {
|
||||||
|
captchaEnabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var captchaEnabled bool
|
|
||||||
if user != nil && user.SigninWrongTimes >= failedSigninLimit {
|
|
||||||
captchaEnabled = true
|
|
||||||
}
|
|
||||||
c.ResponseOk(captchaEnabled)
|
c.ResponseOk(captchaEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,7 +1001,7 @@ func (c *ApiController) GetCaptchaStatus() {
|
|||||||
// @Title Callback
|
// @Title Callback
|
||||||
// @Tag Callback API
|
// @Tag Callback API
|
||||||
// @Description Get Login Error Counts
|
// @Description Get Login Error Counts
|
||||||
// @router /api/Callback [post]
|
// @router /Callback [post]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) Callback() {
|
func (c *ApiController) Callback() {
|
||||||
code := c.GetString("code")
|
code := c.GetString("code")
|
||||||
|
@@ -24,12 +24,13 @@ import (
|
|||||||
|
|
||||||
// Enforce
|
// Enforce
|
||||||
// @Title Enforce
|
// @Title Enforce
|
||||||
// @Tag Enforce API
|
// @Tag Enforcer API
|
||||||
// @Description Call Casbin Enforce API
|
// @Description Call Casbin Enforce API
|
||||||
// @Param body body object.CasbinRequest true "Casbin request"
|
// @Param body body []string true "Casbin request"
|
||||||
// @Param permissionId query string false "permission id"
|
// @Param permissionId query string false "permission id"
|
||||||
// @Param modelId query string false "model id"
|
// @Param modelId query string false "model id"
|
||||||
// @Param resourceId query string false "resource id"
|
// @Param resourceId query string false "resource id"
|
||||||
|
// @Param owner query string false "owner"
|
||||||
// @Success 200 {object} controllers.Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /enforce [post]
|
// @router /enforce [post]
|
||||||
func (c *ApiController) Enforce() {
|
func (c *ApiController) Enforce() {
|
||||||
@@ -37,13 +38,14 @@ func (c *ApiController) Enforce() {
|
|||||||
modelId := c.Input().Get("modelId")
|
modelId := c.Input().Get("modelId")
|
||||||
resourceId := c.Input().Get("resourceId")
|
resourceId := c.Input().Get("resourceId")
|
||||||
enforcerId := c.Input().Get("enforcerId")
|
enforcerId := c.Input().Get("enforcerId")
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
|
||||||
if len(c.Ctx.Input.RequestBody) == 0 {
|
if len(c.Ctx.Input.RequestBody) == 0 {
|
||||||
c.ResponseError("The request body should not be empty")
|
c.ResponseError("The request body should not be empty")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var request object.CasbinRequest
|
var request []string
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
@@ -60,7 +62,10 @@ func (c *ApiController) Enforce() {
|
|||||||
res := []bool{}
|
res := []bool{}
|
||||||
keyRes := []string{}
|
keyRes := []string{}
|
||||||
|
|
||||||
enforceResult, err := enforcer.Enforce(request...)
|
// type transformation
|
||||||
|
interfaceRequest := util.StringToInterfaceArray(request)
|
||||||
|
|
||||||
|
enforceResult, err := enforcer.Enforce(interfaceRequest...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -87,7 +92,7 @@ func (c *ApiController) Enforce() {
|
|||||||
res := []bool{}
|
res := []bool{}
|
||||||
keyRes := []string{}
|
keyRes := []string{}
|
||||||
|
|
||||||
enforceResult, err := object.Enforce(permission, &request)
|
enforceResult, err := object.Enforce(permission, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -114,6 +119,8 @@ func (c *ApiController) Enforce() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else if owner != "" {
|
||||||
|
permissions, err = object.GetPermissions(owner)
|
||||||
} else {
|
} else {
|
||||||
c.ResponseError(c.T("general:Missing parameter"))
|
c.ResponseError(c.T("general:Missing parameter"))
|
||||||
return
|
return
|
||||||
@@ -129,7 +136,7 @@ func (c *ApiController) Enforce() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
enforceResult, err := object.Enforce(firstPermission, &request, permissionIds...)
|
enforceResult, err := object.Enforce(firstPermission, request, permissionIds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -144,19 +151,21 @@ func (c *ApiController) Enforce() {
|
|||||||
|
|
||||||
// BatchEnforce
|
// BatchEnforce
|
||||||
// @Title BatchEnforce
|
// @Title BatchEnforce
|
||||||
// @Tag Enforce API
|
// @Tag Enforcer API
|
||||||
// @Description Call Casbin BatchEnforce API
|
// @Description Call Casbin BatchEnforce API
|
||||||
// @Param body body object.CasbinRequest true "array of casbin requests"
|
// @Param body body []string true "array of casbin requests"
|
||||||
// @Param permissionId query string false "permission id"
|
// @Param permissionId query string false "permission id"
|
||||||
// @Param modelId query string false "model id"
|
// @Param modelId query string false "model id"
|
||||||
|
// @Param owner query string false "owner"
|
||||||
// @Success 200 {object} controllers.Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /batch-enforce [post]
|
// @router /batch-enforce [post]
|
||||||
func (c *ApiController) BatchEnforce() {
|
func (c *ApiController) BatchEnforce() {
|
||||||
permissionId := c.Input().Get("permissionId")
|
permissionId := c.Input().Get("permissionId")
|
||||||
modelId := c.Input().Get("modelId")
|
modelId := c.Input().Get("modelId")
|
||||||
enforcerId := c.Input().Get("enforcerId")
|
enforcerId := c.Input().Get("enforcerId")
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
|
||||||
var requests []object.CasbinRequest
|
var requests [][]string
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
@@ -173,7 +182,10 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
res := [][]bool{}
|
res := [][]bool{}
|
||||||
keyRes := []string{}
|
keyRes := []string{}
|
||||||
|
|
||||||
enforceResult, err := enforcer.BatchEnforce(requests)
|
// type transformation
|
||||||
|
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||||
|
|
||||||
|
enforceResult, err := enforcer.BatchEnforce(interfaceRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -200,7 +212,7 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
res := [][]bool{}
|
res := [][]bool{}
|
||||||
keyRes := []string{}
|
keyRes := []string{}
|
||||||
|
|
||||||
enforceResult, err := object.BatchEnforce(permission, &requests)
|
enforceResult, err := object.BatchEnforce(permission, requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -221,6 +233,8 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else if owner != "" {
|
||||||
|
permissions, err = object.GetPermissions(owner)
|
||||||
} else {
|
} else {
|
||||||
c.ResponseError(c.T("general:Missing parameter"))
|
c.ResponseError(c.T("general:Missing parameter"))
|
||||||
return
|
return
|
||||||
@@ -236,7 +250,7 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
enforceResult, err := object.BatchEnforce(firstPermission, &requests, permissionIds...)
|
enforceResult, err := object.BatchEnforce(firstPermission, requests, permissionIds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -250,10 +264,13 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetAllObjects() {
|
func (c *ApiController) GetAllObjects() {
|
||||||
userId := c.GetSessionUsername()
|
userId := c.Input().Get("userId")
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
c.ResponseError(c.T("general:Please login first"))
|
userId = c.GetSessionUsername()
|
||||||
return
|
if userId == "" {
|
||||||
|
c.ResponseError(c.T("general:Please login first"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objects, err := object.GetAllObjects(userId)
|
objects, err := object.GetAllObjects(userId)
|
||||||
@@ -266,10 +283,13 @@ func (c *ApiController) GetAllObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetAllActions() {
|
func (c *ApiController) GetAllActions() {
|
||||||
userId := c.GetSessionUsername()
|
userId := c.Input().Get("userId")
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
c.ResponseError(c.T("general:Please login first"))
|
userId = c.GetSessionUsername()
|
||||||
return
|
if userId == "" {
|
||||||
|
c.ResponseError(c.T("general:Please login first"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actions, err := object.GetAllActions(userId)
|
actions, err := object.GetAllActions(userId)
|
||||||
@@ -282,10 +302,13 @@ func (c *ApiController) GetAllActions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetAllRoles() {
|
func (c *ApiController) GetAllRoles() {
|
||||||
userId := c.GetSessionUsername()
|
userId := c.Input().Get("userId")
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
c.ResponseError(c.T("general:Please login first"))
|
userId = c.GetSessionUsername()
|
||||||
return
|
if userId == "" {
|
||||||
|
c.ResponseError(c.T("general:Please login first"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := object.GetAllRoles(userId)
|
roles, err := object.GetAllRoles(userId)
|
||||||
|
@@ -39,13 +39,13 @@ func (c *ApiController) GetCerts() {
|
|||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
maskedCerts, err := object.GetMaskedCerts(object.GetCerts(owner))
|
certs, err := object.GetMaskedCerts(object.GetCerts(owner))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedCerts)
|
c.ResponseOk(certs)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetCertCount(owner, field, value)
|
count, err := object.GetCertCount(owner, field, value)
|
||||||
@@ -80,13 +80,13 @@ func (c *ApiController) GetGlobalCerts() {
|
|||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
maskedCerts, err := object.GetMaskedCerts(object.GetGlobalCerts())
|
certs, err := object.GetMaskedCerts(object.GetGlobalCerts())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedCerts)
|
c.ResponseOk(certs)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetGlobalCertsCount(field, value)
|
count, err := object.GetGlobalCertsCount(field, value)
|
||||||
|
@@ -138,7 +138,7 @@ func (c *ApiController) AddEnforcer() {
|
|||||||
// @Title DeleteEnforcer
|
// @Title DeleteEnforcer
|
||||||
// @Tag Enforcer API
|
// @Tag Enforcer API
|
||||||
// @Description delete enforcer
|
// @Description delete enforcer
|
||||||
// @Param body body object.Enforce true "The enforcer object"
|
// @Param body body object.Enforcer true "The enforcer object"
|
||||||
// @Success 200 {object} object.Enforcer
|
// @Success 200 {object} object.Enforcer
|
||||||
// @router /delete-enforcer [post]
|
// @router /delete-enforcer [post]
|
||||||
func (c *ApiController) DeleteEnforcer() {
|
func (c *ApiController) DeleteEnforcer() {
|
||||||
|
@@ -18,7 +18,7 @@ import "github.com/casdoor/casdoor/object"
|
|||||||
|
|
||||||
// GetDashboard
|
// GetDashboard
|
||||||
// @Title GetDashboard
|
// @Title GetDashboard
|
||||||
// @Tag GetDashboard API
|
// @Tag System API
|
||||||
// @Description get information of dashboard
|
// @Description get information of dashboard
|
||||||
// @Success 200 {object} controllers.Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /get-dashboard [get]
|
// @router /get-dashboard [get]
|
||||||
|
164
controllers/invitation.go
Normal file
164
controllers/invitation.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/beego/beego/utils/pagination"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetInvitations
|
||||||
|
// @Title GetInvitations
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description get invitations
|
||||||
|
// @Param owner query string true "The owner of invitations"
|
||||||
|
// @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")
|
||||||
|
|
||||||
|
if limit == "" || page == "" {
|
||||||
|
invitations, err := object.GetInvitations(owner)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(invitations)
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
count, err := object.GetInvitationCount(owner, field, value)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||||
|
invitations, err := object.GetPaginationInvitations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(invitations, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInvitation
|
||||||
|
// @Title GetInvitation
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description get invitation
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the invitation"
|
||||||
|
// @Success 200 {object} object.Invitation The Response object
|
||||||
|
// @router /get-invitation [get]
|
||||||
|
func (c *ApiController) GetInvitation() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
invitation, err := object.GetInvitation(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(invitation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateInvitation
|
||||||
|
// @Title UpdateInvitation
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description update invitation
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the invitation"
|
||||||
|
// @Param body body object.Invitation true "The details of the invitation"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /update-invitation [post]
|
||||||
|
func (c *ApiController) UpdateInvitation() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var invitation object.Invitation
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.UpdateInvitation(id, &invitation))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInvitation
|
||||||
|
// @Title AddInvitation
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description add invitation
|
||||||
|
// @Param body body object.Invitation true "The details of the invitation"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /add-invitation [post]
|
||||||
|
func (c *ApiController) AddInvitation() {
|
||||||
|
var invitation object.Invitation
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddInvitation(&invitation))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteInvitation
|
||||||
|
// @Title DeleteInvitation
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description delete invitation
|
||||||
|
// @Param body body object.Invitation true "The details of the invitation"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /delete-invitation [post]
|
||||||
|
func (c *ApiController) DeleteInvitation() {
|
||||||
|
var invitation object.Invitation
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.DeleteInvitation(&invitation))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyInvitation
|
||||||
|
// @Title VerifyInvitation
|
||||||
|
// @Tag Invitation API
|
||||||
|
// @Description verify invitation
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the invitation"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /verify-invitation [get]
|
||||||
|
func (c *ApiController) VerifyInvitation() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
payment, attachInfo, err := object.VerifyInvitation(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(payment, attachInfo)
|
||||||
|
}
|
@@ -42,7 +42,7 @@ type LdapSyncResp struct {
|
|||||||
// @Tag Account API
|
// @Tag Account API
|
||||||
// @Description get ldap users
|
// @Description get ldap users
|
||||||
// Param id string true "id"
|
// Param id string true "id"
|
||||||
// @Success 200 {object} LdapResp The Response object
|
// @Success 200 {object} controllers.LdapResp The Response object
|
||||||
// @router /get-ldap-users [get]
|
// @router /get-ldap-users [get]
|
||||||
func (c *ApiController) GetLdapUsers() {
|
func (c *ApiController) GetLdapUsers() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
@@ -250,7 +250,7 @@ func (c *ApiController) DeleteLdap() {
|
|||||||
// @Tag Account API
|
// @Tag Account API
|
||||||
// @Description sync ldap users
|
// @Description sync ldap users
|
||||||
// @Param id query string true "id"
|
// @Param id query string true "id"
|
||||||
// @Success 200 {object} LdapSyncResp The Response object
|
// @Success 200 {object} controllers.LdapSyncResp The Response object
|
||||||
// @router /sync-ldap-users [post]
|
// @router /sync-ldap-users [post]
|
||||||
func (c *ApiController) SyncLdapUsers() {
|
func (c *ApiController) SyncLdapUsers() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
|
@@ -73,7 +73,7 @@ func (c *ApiController) MfaSetupInitiate() {
|
|||||||
// @Description setup verify totp
|
// @Description setup verify totp
|
||||||
// @param secret form string true "MFA secret"
|
// @param secret form string true "MFA secret"
|
||||||
// @param passcode form string true "MFA passcode"
|
// @param passcode form string true "MFA passcode"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /mfa/setup/verify [post]
|
// @router /mfa/setup/verify [post]
|
||||||
func (c *ApiController) MfaSetupVerify() {
|
func (c *ApiController) MfaSetupVerify() {
|
||||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||||
@@ -104,7 +104,7 @@ func (c *ApiController) MfaSetupVerify() {
|
|||||||
// @param owner form string true "owner of user"
|
// @param owner form string true "owner of user"
|
||||||
// @param name form string true "name of user"
|
// @param name form string true "name of user"
|
||||||
// @param type form string true "MFA auth type"
|
// @param type form string true "MFA auth type"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /mfa/setup/enable [post]
|
// @router /mfa/setup/enable [post]
|
||||||
func (c *ApiController) MfaSetupEnable() {
|
func (c *ApiController) MfaSetupEnable() {
|
||||||
owner := c.Ctx.Request.Form.Get("owner")
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
@@ -143,7 +143,7 @@ func (c *ApiController) MfaSetupEnable() {
|
|||||||
// @Description: Delete MFA
|
// @Description: Delete MFA
|
||||||
// @param owner form string true "owner of user"
|
// @param owner form string true "owner of user"
|
||||||
// @param name form string true "name of user"
|
// @param name form string true "name of user"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /delete-mfa/ [post]
|
// @router /delete-mfa/ [post]
|
||||||
func (c *ApiController) DeleteMfa() {
|
func (c *ApiController) DeleteMfa() {
|
||||||
owner := c.Ctx.Request.Form.Get("owner")
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
@@ -176,7 +176,7 @@ func (c *ApiController) DeleteMfa() {
|
|||||||
// @param owner form string true "owner of user"
|
// @param owner form string true "owner of user"
|
||||||
// @param name form string true "name of user"
|
// @param name form string true "name of user"
|
||||||
// @param id form string true "id of user's MFA props"
|
// @param id form string true "id of user's MFA props"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /set-preferred-mfa [post]
|
// @router /set-preferred-mfa [post]
|
||||||
func (c *ApiController) SetPreferredMfa() {
|
func (c *ApiController) SetPreferredMfa() {
|
||||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||||
|
@@ -41,13 +41,12 @@ func (c *ApiController) GetOrganizations() {
|
|||||||
|
|
||||||
isGlobalAdmin := c.IsGlobalAdmin()
|
isGlobalAdmin := c.IsGlobalAdmin()
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
var maskedOrganizations []*object.Organization
|
var organizations []*object.Organization
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if isGlobalAdmin {
|
if isGlobalAdmin {
|
||||||
maskedOrganizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner))
|
organizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner))
|
||||||
} else {
|
} else {
|
||||||
maskedOrganizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
|
organizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,15 +54,15 @@ func (c *ApiController) GetOrganizations() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedOrganizations)
|
c.ResponseOk(organizations)
|
||||||
} else {
|
} else {
|
||||||
if !isGlobalAdmin {
|
if !isGlobalAdmin {
|
||||||
maskedOrganizations, err := object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
|
organizations, err := object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.ResponseOk(maskedOrganizations)
|
c.ResponseOk(organizations)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetOrganizationCount(owner, field, value)
|
count, err := object.GetOrganizationCount(owner, field, value)
|
||||||
@@ -93,13 +92,13 @@ func (c *ApiController) GetOrganizations() {
|
|||||||
// @router /get-organization [get]
|
// @router /get-organization [get]
|
||||||
func (c *ApiController) GetOrganization() {
|
func (c *ApiController) GetOrganization() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
maskedOrganization, err := object.GetMaskedOrganization(object.GetOrganization(id))
|
organization, err := object.GetMaskedOrganization(object.GetOrganization(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedOrganization)
|
c.ResponseOk(organization)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOrganization ...
|
// UpdateOrganization ...
|
||||||
@@ -178,7 +177,7 @@ func (c *ApiController) DeleteOrganization() {
|
|||||||
// @Tag Organization API
|
// @Tag Organization API
|
||||||
// @Description get default application
|
// @Description get default application
|
||||||
// @Param id query string true "organization id"
|
// @Param id query string true "organization id"
|
||||||
// @Success 200 {object} Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /get-default-application [get]
|
// @router /get-default-application [get]
|
||||||
func (c *ApiController) GetDefaultApplication() {
|
func (c *ApiController) GetDefaultApplication() {
|
||||||
userId := c.GetSessionUsername()
|
userId := c.GetSessionUsername()
|
||||||
@@ -190,8 +189,8 @@ func (c *ApiController) GetDefaultApplication() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
maskedApplication := object.GetMaskedApplication(application, userId)
|
application = object.GetMaskedApplication(application, userId)
|
||||||
c.ResponseOk(maskedApplication)
|
c.ResponseOk(application)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrganizationNames ...
|
// GetOrganizationNames ...
|
||||||
|
@@ -20,7 +20,7 @@ import (
|
|||||||
|
|
||||||
// GetPrometheusInfo
|
// GetPrometheusInfo
|
||||||
// @Title GetPrometheusInfo
|
// @Title GetPrometheusInfo
|
||||||
// @Tag Prometheus API
|
// @Tag System API
|
||||||
// @Description get Prometheus Info
|
// @Description get Prometheus Info
|
||||||
// @Success 200 {object} object.PrometheusInfo The Response object
|
// @Success 200 {object} object.PrometheusInfo The Response object
|
||||||
// @router /get-prometheus-info [get]
|
// @router /get-prometheus-info [get]
|
||||||
|
@@ -51,9 +51,14 @@ type NotificationForm struct {
|
|||||||
// @Param clientId query string true "The clientId of the application"
|
// @Param clientId query string true "The clientId of the application"
|
||||||
// @Param clientSecret query string true "The clientSecret of the application"
|
// @Param clientSecret query string true "The clientSecret of the application"
|
||||||
// @Param from body controllers.EmailForm true "Details of the email request"
|
// @Param from body controllers.EmailForm true "Details of the email request"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /api/send-email [post]
|
// @router /send-email [post]
|
||||||
func (c *ApiController) SendEmail() {
|
func (c *ApiController) SendEmail() {
|
||||||
|
userId, ok := c.RequireSignedIn()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var emailForm EmailForm
|
var emailForm EmailForm
|
||||||
|
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
|
||||||
@@ -108,8 +113,22 @@ func (c *ApiController) SendEmail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
code := "123456"
|
code := "123456"
|
||||||
|
|
||||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||||
content := fmt.Sprintf(emailForm.Content, code)
|
content := strings.Replace(provider.Content, "%s", code, 1)
|
||||||
|
if !strings.HasPrefix(userId, "app/") {
|
||||||
|
var user *object.User
|
||||||
|
user, err = object.GetUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, receiver := range emailForm.Receivers {
|
for _, receiver := range emailForm.Receivers {
|
||||||
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
|
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -128,8 +147,8 @@ func (c *ApiController) SendEmail() {
|
|||||||
// @Param clientId query string true "The clientId of the application"
|
// @Param clientId query string true "The clientId of the application"
|
||||||
// @Param clientSecret query string true "The clientSecret of the application"
|
// @Param clientSecret query string true "The clientSecret of the application"
|
||||||
// @Param from body controllers.SmsForm true "Details of the sms request"
|
// @Param from body controllers.SmsForm true "Details of the sms request"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /api/send-sms [post]
|
// @router /send-sms [post]
|
||||||
func (c *ApiController) SendSms() {
|
func (c *ApiController) SendSms() {
|
||||||
provider, err := c.GetProviderFromContext("SMS")
|
provider, err := c.GetProviderFromContext("SMS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -166,8 +185,8 @@ func (c *ApiController) SendSms() {
|
|||||||
// @Tag Service API
|
// @Tag Service API
|
||||||
// @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
// @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
||||||
// @Param from body controllers.NotificationForm true "Details of the notification request"
|
// @Param from body controllers.NotificationForm true "Details of the notification request"
|
||||||
// @Success 200 {object} Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /api/send-notification [post]
|
// @router /send-notification [post]
|
||||||
func (c *ApiController) SendNotification() {
|
func (c *ApiController) SendNotification() {
|
||||||
provider, err := c.GetProviderFromContext("Notification")
|
provider, err := c.GetProviderFromContext("Notification")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -40,13 +40,13 @@ func (c *ApiController) GetSyncers() {
|
|||||||
organization := c.Input().Get("organization")
|
organization := c.Input().Get("organization")
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
organizationSyncers, err := object.GetOrganizationSyncers(owner, organization)
|
syncers, err := object.GetMaskedSyncers(object.GetOrganizationSyncers(owner, organization))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(organizationSyncers)
|
c.ResponseOk(syncers)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetSyncerCount(owner, organization, field, value)
|
count, err := object.GetSyncerCount(owner, organization, field, value)
|
||||||
@@ -56,7 +56,7 @@ func (c *ApiController) GetSyncers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||||
syncers, err := object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
syncers, err := object.GetMaskedSyncers(object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -76,7 +76,7 @@ func (c *ApiController) GetSyncers() {
|
|||||||
func (c *ApiController) GetSyncer() {
|
func (c *ApiController) GetSyncer() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
syncer, err := object.GetSyncer(id)
|
syncer, err := object.GetMaskedSyncer(object.GetSyncer(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -156,7 +156,7 @@ func (c *ApiController) DeleteToken() {
|
|||||||
// @Success 200 {object} object.TokenWrapper The Response object
|
// @Success 200 {object} object.TokenWrapper The Response object
|
||||||
// @Success 400 {object} object.TokenError The Response object
|
// @Success 400 {object} object.TokenError The Response object
|
||||||
// @Success 401 {object} object.TokenError The Response object
|
// @Success 401 {object} object.TokenError The Response object
|
||||||
// @router api/login/oauth/access_token [post]
|
// @router /login/oauth/access_token [post]
|
||||||
func (c *ApiController) GetOAuthToken() {
|
func (c *ApiController) GetOAuthToken() {
|
||||||
clientId := c.Input().Get("client_id")
|
clientId := c.Input().Get("client_id")
|
||||||
clientSecret := c.Input().Get("client_secret")
|
clientSecret := c.Input().Get("client_secret")
|
||||||
@@ -273,6 +273,7 @@ func (c *ApiController) RefreshToken() {
|
|||||||
|
|
||||||
// IntrospectToken
|
// IntrospectToken
|
||||||
// @Title IntrospectToken
|
// @Title IntrospectToken
|
||||||
|
// @Tag Login API
|
||||||
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a
|
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a
|
||||||
// parameter representing an OAuth 2.0 token and returns a JSON document
|
// parameter representing an OAuth 2.0 token and returns a JSON document
|
||||||
// representing the meta information surrounding the
|
// representing the meta information surrounding the
|
||||||
|
@@ -39,13 +39,13 @@ func (c *ApiController) GetGlobalUsers() {
|
|||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetGlobalUsers())
|
users, err := object.GetMaskedUsers(object.GetGlobalUsers())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedUsers)
|
c.ResponseOk(users)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetGlobalUserCount(field, value)
|
count, err := object.GetGlobalUserCount(field, value)
|
||||||
@@ -90,22 +90,22 @@ func (c *ApiController) GetUsers() {
|
|||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
if groupName != "" {
|
if groupName != "" {
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
|
users, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.ResponseOk(maskedUsers)
|
c.ResponseOk(users)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetUsers(owner))
|
users, err := object.GetMaskedUsers(object.GetUsers(owner))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedUsers)
|
c.ResponseOk(users)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetUserCount(owner, field, value, groupName)
|
count, err := object.GetUserCount(owner, field, value, groupName)
|
||||||
@@ -175,26 +175,6 @@ func (c *ApiController) GetUser() {
|
|||||||
owner = util.GetOwnerFromId(id)
|
owner = util.GetOwnerFromId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var organization *object.Organization
|
|
||||||
organization, err = object.GetOrganization(util.GetId("admin", owner))
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if organization == nil {
|
|
||||||
c.ResponseError(fmt.Sprintf("the organization: %s is not found", owner))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !organization.IsProfilePublic {
|
|
||||||
requestUserId := c.GetSessionUsername()
|
|
||||||
hasPermission, err := object.CheckUserPermission(requestUserId, id, false, c.GetAcceptLanguage())
|
|
||||||
if !hasPermission {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case email != "":
|
case email != "":
|
||||||
user, err = object.GetUserByEmail(owner, email)
|
user, err = object.GetUserByEmail(owner, email)
|
||||||
@@ -212,6 +192,29 @@ func (c *ApiController) GetUser() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
var organization *object.Organization
|
||||||
|
organization, err = object.GetOrganizationByUser(user)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if organization == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf("the organization: %s is not found", owner))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !organization.IsProfilePublic {
|
||||||
|
requestUserId := c.GetSessionUsername()
|
||||||
|
var hasPermission bool
|
||||||
|
hasPermission, err = object.CheckUserPermission(requestUserId, user.GetId(), false, c.GetAcceptLanguage())
|
||||||
|
if !hasPermission {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if user != nil {
|
if user != nil {
|
||||||
user.MultiFactorAuths = object.GetAllMfaProps(user, true)
|
user.MultiFactorAuths = object.GetAllMfaProps(user, true)
|
||||||
}
|
}
|
||||||
@@ -223,13 +226,13 @@ func (c *ApiController) GetUser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAdminOrSelf := c.IsAdminOrSelf(user)
|
isAdminOrSelf := c.IsAdminOrSelf(user)
|
||||||
maskedUser, err := object.GetMaskedUser(user, isAdminOrSelf)
|
user, err = object.GetMaskedUser(user, isAdminOrSelf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedUser)
|
c.ResponseOk(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser
|
// UpdateUser
|
||||||
@@ -541,13 +544,13 @@ func (c *ApiController) GetSortedUsers() {
|
|||||||
sorter := c.Input().Get("sorter")
|
sorter := c.Input().Get("sorter")
|
||||||
limit := util.ParseInt(c.Input().Get("limit"))
|
limit := util.ParseInt(c.Input().Get("limit"))
|
||||||
|
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
|
users, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(maskedUsers)
|
c.ResponseOk(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserCount
|
// GetUserCount
|
||||||
|
@@ -109,6 +109,15 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if user == nil || user.IsDeleted {
|
||||||
|
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.IsForbidden {
|
||||||
|
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mfaUserSession != "", means method is MfaAuthVerification
|
// mfaUserSession != "", means method is MfaAuthVerification
|
||||||
@@ -272,7 +281,7 @@ func (c *ApiController) VerifyCaptcha() {
|
|||||||
// ResetEmailOrPhone ...
|
// ResetEmailOrPhone ...
|
||||||
// @Tag Account API
|
// @Tag Account API
|
||||||
// @Title ResetEmailOrPhone
|
// @Title ResetEmailOrPhone
|
||||||
// @router /api/reset-email-or-phone [post]
|
// @router /reset-email-or-phone [post]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) ResetEmailOrPhone() {
|
func (c *ApiController) ResetEmailOrPhone() {
|
||||||
user, ok := c.RequireSignedInUser()
|
user, ok := c.RequireSignedInUser()
|
||||||
@@ -367,7 +376,7 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
// VerifyCode
|
// VerifyCode
|
||||||
// @Tag Verification API
|
// @Tag Verification API
|
||||||
// @Title VerifyCode
|
// @Title VerifyCode
|
||||||
// @router /api/verify-code [post]
|
// @router /verify-code [post]
|
||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
func (c *ApiController) VerifyCode() {
|
func (c *ApiController) VerifyCode() {
|
||||||
var authForm form.AuthForm
|
var authForm form.AuthForm
|
||||||
|
15
form/auth.go
15
form/auth.go
@@ -14,8 +14,11 @@
|
|||||||
|
|
||||||
package form
|
package form
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
type AuthForm struct {
|
type AuthForm struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
SigninMethod string `json:"signinMethod"`
|
||||||
|
|
||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -59,3 +62,13 @@ type AuthForm struct {
|
|||||||
Plan string `json:"plan"`
|
Plan string `json:"plan"`
|
||||||
Pricing string `json:"pricing"`
|
Pricing string `json:"pricing"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAuthFormFieldValue(form *AuthForm, fieldName string) (bool, string) {
|
||||||
|
val := reflect.ValueOf(*form)
|
||||||
|
fieldValue := val.FieldByName(fieldName)
|
||||||
|
|
||||||
|
if fieldValue.IsValid() && fieldValue.Kind() == reflect.String {
|
||||||
|
return true, fieldValue.String()
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
4
go.mod
4
go.mod
@@ -12,7 +12,7 @@ require (
|
|||||||
github.com/casdoor/go-sms-sender v0.19.0
|
github.com/casdoor/go-sms-sender v0.19.0
|
||||||
github.com/casdoor/gomail/v2 v2.0.1
|
github.com/casdoor/gomail/v2 v2.0.1
|
||||||
github.com/casdoor/notify v0.45.0
|
github.com/casdoor/notify v0.45.0
|
||||||
github.com/casdoor/oss v1.4.1
|
github.com/casdoor/oss v1.5.0
|
||||||
github.com/casdoor/xorm-adapter/v3 v3.1.0
|
github.com/casdoor/xorm-adapter/v3 v3.1.0
|
||||||
github.com/casvisor/casvisor-go-sdk v1.0.3
|
github.com/casvisor/casvisor-go-sdk v1.0.3
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
@@ -35,7 +35,7 @@ require (
|
|||||||
github.com/lestrrat-go/jwx v1.2.21
|
github.com/lestrrat-go/jwx v1.2.21
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||||
github.com/markbates/goth v1.75.2
|
github.com/markbates/goth v1.78.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/nyaruka/phonenumbers v1.1.5
|
github.com/nyaruka/phonenumbers v1.1.5
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
|
8
go.sum
8
go.sum
@@ -1089,8 +1089,8 @@ github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR
|
|||||||
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
|
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
|
||||||
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=
|
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=
|
||||||
github.com/casdoor/notify v0.45.0/go.mod h1:wNHQu0tiDROMBIvz0j3Om3Lhd5yZ+AIfnFb8MYb8OLQ=
|
github.com/casdoor/notify v0.45.0/go.mod h1:wNHQu0tiDROMBIvz0j3Om3Lhd5yZ+AIfnFb8MYb8OLQ=
|
||||||
github.com/casdoor/oss v1.4.1 h1:/P2JCyGzB2TtpJ3LocKocI1VAme2YdvVau2wpMQGt7I=
|
github.com/casdoor/oss v1.5.0 h1:mi1htaXR5fynskDry1S3wk+Dd2nRY1z1pVcnGsqMqP4=
|
||||||
github.com/casdoor/oss v1.4.1/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
|
github.com/casdoor/oss v1.5.0/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
|
||||||
github.com/casdoor/xorm-adapter/v3 v3.1.0 h1:NodWayRtSLVSeCvL9H3Hc61k0G17KhV9IymTCNfh3kk=
|
github.com/casdoor/xorm-adapter/v3 v3.1.0 h1:NodWayRtSLVSeCvL9H3Hc61k0G17KhV9IymTCNfh3kk=
|
||||||
github.com/casdoor/xorm-adapter/v3 v3.1.0/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
|
github.com/casdoor/xorm-adapter/v3 v3.1.0/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
|
||||||
github.com/casvisor/casvisor-go-sdk v1.0.3 h1:TKJQWKnhtznEBhzLPEdNsp7nJK2GgdD8JsB0lFPMW7U=
|
github.com/casvisor/casvisor-go-sdk v1.0.3 h1:TKJQWKnhtznEBhzLPEdNsp7nJK2GgdD8JsB0lFPMW7U=
|
||||||
@@ -1657,8 +1657,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
|||||||
github.com/mailgun/mailgun-go/v4 v4.11.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
github.com/mailgun/mailgun-go/v4 v4.11.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
||||||
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
||||||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
||||||
github.com/markbates/goth v1.75.2 h1:C7KloBMMk50JyXaHhzfqWYLW6+bDcSVIvUGHXneLWro=
|
github.com/markbates/goth v1.78.0 h1:7VEIFDycJp9deyVv3YraGBPdD0ZYQW93Y3Aw1eVP3BY=
|
||||||
github.com/markbates/goth v1.75.2/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
|
github.com/markbates/goth v1.78.0/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
|
||||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
|
||||||
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
|
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
|
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
|
||||||
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
|
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
|
||||||
"Unauthorized operation": "Nicht autorisierte Operation",
|
"Unauthorized operation": "Nicht autorisierte Operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
|
||||||
"The application: %s does not exist": "La aplicación: %s no existe",
|
"The application: %s does not exist": "La aplicación: %s no existe",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
|
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
|
||||||
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
|
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
|
||||||
"Unauthorized operation": "Operación no autorizada",
|
"Unauthorized operation": "Operación no autorizada",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
|
||||||
"The application: %s does not exist": "L'application : %s n'existe pas",
|
"The application: %s does not exist": "L'application : %s n'existe pas",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
|
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
|
||||||
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
|
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
|
||||||
"Unauthorized operation": "Opération non autorisée",
|
"Unauthorized operation": "Opération non autorisée",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk provider: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk provider: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
|
||||||
"The application: %s does not exist": "Aplikasi: %s tidak ada",
|
"The application: %s does not exist": "Aplikasi: %s tidak ada",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut",
|
"The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut",
|
||||||
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
|
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
|
||||||
"Unauthorized operation": "Operasi tidak sah",
|
"Unauthorized operation": "Operasi tidak sah",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "プロバイダー名:%sとユーザー名:%s(%s)のアカウントは存在しません。新しいアカウントとしてサインアップすることはできません。 ITサポートに連絡してください",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "プロバイダー名:%sとユーザー名:%s(%s)のアカウントは存在しません。新しいアカウントとしてサインアップすることはできません。 ITサポートに連絡してください",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "プロバイダのアカウント:%s とユーザー名:%s (%s) は既に別のアカウント:%s (%s) にリンクされています",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "プロバイダのアカウント:%s とユーザー名:%s (%s) は既に別のアカウント:%s (%s) にリンクされています",
|
||||||
"The application: %s does not exist": "アプリケーション: %sは存在しません",
|
"The application: %s does not exist": "アプリケーション: %sは存在しません",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
|
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
|
||||||
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
|
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
|
||||||
"Unauthorized operation": "不正操作",
|
"Unauthorized operation": "不正操作",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "공급자 계정 %s과 사용자 이름 %s (%s)는 존재하지 않으며 새 계정으로 등록할 수 없습니다. IT 지원팀에 문의하십시오",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "공급자 계정 %s과 사용자 이름 %s (%s)는 존재하지 않으며 새 계정으로 등록할 수 없습니다. IT 지원팀에 문의하십시오",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "공급자 계정 %s과 사용자 이름 %s(%s)는 이미 다른 계정 %s(%s)에 연결되어 있습니다",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "공급자 계정 %s과 사용자 이름 %s(%s)는 이미 다른 계정 %s(%s)에 연결되어 있습니다",
|
||||||
"The application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
|
"The application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
|
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
|
||||||
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
|
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
|
||||||
"Unauthorized operation": "무단 조작",
|
"Unauthorized operation": "무단 조작",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -1,20 +1,23 @@
|
|||||||
{
|
{
|
||||||
"account": {
|
"account": {
|
||||||
"Failed to add user": "Failed to add user",
|
"Failed to add user": "Falha ao adicionar usuário",
|
||||||
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
"Get init score failed, error: %w": "Obter pontuação inicial falhou, erro: %w",
|
||||||
"Please sign out first": "Please sign out first",
|
"Please sign out first": "Por favor, saia da sessão primeiro",
|
||||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
"The application does not allow to sign up new account": "O aplicativo não permite a criação de uma nova conta"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"Challenge method should be S256": "Challenge method should be S256",
|
"Challenge method should be S256": "Método de desafio deve ser S256",
|
||||||
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
"Failed to create user, user information is invalid: %s": "Falha ao criar usuário, informação do usuário inválida: %s",
|
||||||
"Failed to login in: %s": "Failed to login in: %s",
|
"Failed to login in: %s": "Falha ao entrar em: %s",
|
||||||
"Invalid token": "Invalid token",
|
"Invalid token": "Token inválido",
|
||||||
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
"State expected: %s, but got: %s": "Estado esperado: %s, mas recebeu: %s",
|
||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta via %%s, por favor, use outra forma de se inscrever",
|
||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta entre em contato com seu suporte de TI",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
@@ -50,12 +53,12 @@
|
|||||||
"Username already exists": "Username already exists",
|
"Username already exists": "Username already exists",
|
||||||
"Username cannot be an email address": "Username cannot be an email address",
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
"Username cannot start with a digit": "Username cannot start with a digit",
|
"Username cannot start with a digit": "O nome de usuário não pode começar com um dígito",
|
||||||
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
"Username is too long (maximum is 39 characters).": "Nome de usuário é muito longo (máximo é 39 caracteres).",
|
||||||
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
"Username must have at least 2 characters": "Nome de usuário deve ter pelo menos 2 caracteres",
|
||||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
"password or code is incorrect": "password or code is incorrect",
|
"password or code is incorrect": "senha ou código incorreto",
|
||||||
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
"unsupported password type: %s": "unsupported password type: %s"
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
},
|
},
|
||||||
@@ -79,15 +82,15 @@
|
|||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
"The %s is immutable.": "The %s is immutable.",
|
"The %s is immutable.": "O %s é imutável.",
|
||||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
"Unknown modify rule %s.": "Regra de modificação %s desconhecida."
|
||||||
},
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
"Invalid application id": "Invalid application id",
|
"Invalid application id": "Id do aplicativo inválido",
|
||||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
"the provider: %s does not exist": "o provedor: %s não existe"
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource": {
|
||||||
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
"User is nil for tag: avatar": "Usuário é nulo para tag: avatar",
|
||||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
},
|
},
|
||||||
"saml": {
|
"saml": {
|
||||||
@@ -106,19 +109,19 @@
|
|||||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
"Empty clientId or clientSecret": "ClientId ou clientSecret vazio",
|
||||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret errado",
|
||||||
"Invalid client_id": "Invalid client_id",
|
"Invalid client_id": "client_id inválido",
|
||||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI de redirecionamento: %s não existe na lista de URI de redirecionamento permitida",
|
||||||
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
"Token not found, invalid accessToken": "Token não encontrado, token de acesso inválido"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"Display name cannot be empty": "Display name cannot be empty",
|
"Display name cannot be empty": "Nome de exibição não pode ser vazio",
|
||||||
"New password cannot contain blank space.": "New password cannot contain blank space."
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
},
|
},
|
||||||
"user_upload": {
|
"user_upload": {
|
||||||
"Failed to import users": "Failed to import users"
|
"Failed to import users": "Falha ao importar usuários"
|
||||||
},
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"No application is found for userId: %s": "No application is found for userId: %s",
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
"The application does not allow to sign up new account": "Приложение не позволяет зарегистрироваться новому аккаунту"
|
"The application does not allow to sign up new account": "Приложение не позволяет зарегистрироваться новому аккаунту"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"Challenge method should be S256": "Метод испытаний должен быть S256",
|
"Challenge method should be S256": "Метод проверки должен быть S256",
|
||||||
"Failed to create user, user information is invalid: %s": "Не удалось создать пользователя, информация о пользователе недействительна: %s",
|
"Failed to create user, user information is invalid: %s": "Не удалось создать пользователя, информация о пользователе недействительна: %s",
|
||||||
"Failed to login in: %s": "Не удалось войти в систему: %s",
|
"Failed to login in: %s": "Не удалось войти в систему: %s",
|
||||||
"Invalid token": "Недействительный токен",
|
"Invalid token": "Недействительный токен",
|
||||||
@@ -15,11 +15,14 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Аккаунт для провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован как новый аккаунт. Пожалуйста, обратитесь в службу поддержки IT",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Аккаунт для провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован как новый аккаунт. Пожалуйста, обратитесь в службу поддержки IT",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Аккаунт поставщика: %s и имя пользователя: %s (%s) уже связаны с другим аккаунтом: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Аккаунт поставщика: %s и имя пользователя: %s (%s) уже связаны с другим аккаунтом: %s (%s)",
|
||||||
"The application: %s does not exist": "Приложение: %s не существует",
|
"The application: %s does not exist": "Приложение: %s не существует",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
||||||
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
||||||
"Unauthorized operation": "Несанкционированная операция",
|
"Unauthorized operation": "Несанкционированная операция",
|
||||||
"Unknown authentication type (not password or provider), form = %s": "Неизвестный тип аутентификации (не пароль и не провайдер), форма = %s",
|
"Unknown authentication type (not password or provider), form = %s": "Неизвестный тип аутентификации (не пароль и не провайдер), форма = %s",
|
||||||
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
|
"User's tag: %s is not listed in the application's tags": "Тег пользователя: %s не указан в тэгах приложения",
|
||||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"
|
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"
|
||||||
},
|
},
|
||||||
"cas": {
|
"cas": {
|
||||||
@@ -45,7 +48,7 @@
|
|||||||
"Phone number is invalid": "Номер телефона является недействительным",
|
"Phone number is invalid": "Номер телефона является недействительным",
|
||||||
"Session outdated, please login again": "Сессия устарела, пожалуйста, войдите снова",
|
"Session outdated, please login again": "Сессия устарела, пожалуйста, войдите снова",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
|
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
|
||||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
"The user: %s doesn't exist in LDAP server": "Пользователь %s не существует на LDAP сервере",
|
||||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
|
||||||
"Username already exists": "Имя пользователя уже существует",
|
"Username already exists": "Имя пользователя уже существует",
|
||||||
"Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты",
|
"Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты",
|
||||||
@@ -55,7 +58,7 @@
|
|||||||
"Username must have at least 2 characters": "Имя пользователя должно содержать не менее 2 символов",
|
"Username must have at least 2 characters": "Имя пользователя должно содержать не менее 2 символов",
|
||||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Вы ввели неправильный пароль или код слишком много раз, пожалуйста, подождите %d минут и попробуйте снова",
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Вы ввели неправильный пароль или код слишком много раз, пожалуйста, подождите %d минут и попробуйте снова",
|
||||||
"Your region is not allow to signup by phone": "Ваш регион не разрешает регистрацию по телефону",
|
"Your region is not allow to signup by phone": "Ваш регион не разрешает регистрацию по телефону",
|
||||||
"password or code is incorrect": "password or code is incorrect",
|
"password or code is incorrect": "неправильный пароль или код",
|
||||||
"password or code is incorrect, you have %d remaining chances": "Неправильный пароль или код, у вас осталось %d попыток",
|
"password or code is incorrect, you have %d remaining chances": "Неправильный пароль или код, у вас осталось %d попыток",
|
||||||
"unsupported password type: %s": "неподдерживаемый тип пароля: %s"
|
"unsupported password type: %s": "неподдерживаемый тип пароля: %s"
|
||||||
},
|
},
|
||||||
@@ -63,8 +66,8 @@
|
|||||||
"Missing parameter": "Отсутствующий параметр",
|
"Missing parameter": "Отсутствующий параметр",
|
||||||
"Please login first": "Пожалуйста, сначала войдите в систему",
|
"Please login first": "Пожалуйста, сначала войдите в систему",
|
||||||
"The user: %s doesn't exist": "Пользователь %s не существует",
|
"The user: %s doesn't exist": "Пользователь %s не существует",
|
||||||
"don't support captchaProvider: ": "не поддерживайте captchaProvider:",
|
"don't support captchaProvider: ": "неподдерживаемый captchaProvider: ",
|
||||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
"this operation is not allowed in demo mode": "эта операция не разрешена в демо-режиме"
|
||||||
},
|
},
|
||||||
"ldap": {
|
"ldap": {
|
||||||
"Ldap server exist": "LDAP-сервер существует"
|
"Ldap server exist": "LDAP-сервер существует"
|
||||||
@@ -103,7 +106,7 @@
|
|||||||
},
|
},
|
||||||
"storage": {
|
"storage": {
|
||||||
"The objectKey: %s is not allowed": "Объект «objectKey: %s» не разрешен",
|
"The objectKey: %s is not allowed": "Объект «objectKey: %s» не разрешен",
|
||||||
"The provider type: %s is not supported": "Тип поставщика: %s не поддерживается"
|
"The provider type: %s is not supported": "Тип провайдера: %s не поддерживается"
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"Empty clientId or clientSecret": "Пустой идентификатор клиента или секрет клиента",
|
"Empty clientId or clientSecret": "Пустой идентификатор клиента или секрет клиента",
|
||||||
@@ -122,7 +125,7 @@
|
|||||||
},
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"No application is found for userId: %s": "Не найдено заявки для пользователя с идентификатором: %s",
|
"No application is found for userId: %s": "Не найдено заявки для пользователя с идентификатором: %s",
|
||||||
"No provider for category: %s is found for application: %s": "Нет поставщика для категории: %s для приложения: %s",
|
"No provider for category: %s is found for application: %s": "Нет провайдера для категории: %s для приложения: %s",
|
||||||
"The provider: %s is not found": "Поставщик: %s не найден"
|
"The provider: %s is not found": "Поставщик: %s не найден"
|
||||||
},
|
},
|
||||||
"verification": {
|
"verification": {
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
@@ -40,22 +43,22 @@
|
|||||||
"LastName cannot be blank": "LastName cannot be blank",
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
"Organization does not exist": "Organization does not exist",
|
"Organization does not exist": "Organization does not exist",
|
||||||
"Phone already exists": "Phone already exists",
|
"Phone already exists": "Telefon numarası zaten mevcut",
|
||||||
"Phone cannot be empty": "Phone cannot be empty",
|
"Phone cannot be empty": "Telefon numarası boş olamaz",
|
||||||
"Phone number is invalid": "Phone number is invalid",
|
"Phone number is invalid": "Telefon numarası geçersiz",
|
||||||
"Session outdated, please login again": "Session outdated, please login again",
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
"Username already exists": "Username already exists",
|
"Username already exists": "Kullanıcı adı zaten var",
|
||||||
"Username cannot be an email address": "Username cannot be an email address",
|
"Username cannot be an email address": "Kullanıcı adı bir e-mail adresi olamaz",
|
||||||
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
"Username cannot contain white spaces": "Kullanıcı adı boşluk karakteri içeremez",
|
||||||
"Username cannot start with a digit": "Username cannot start with a digit",
|
"Username cannot start with a digit": "Kullanıcı adı rakamla başlayamaz",
|
||||||
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
"Username is too long (maximum is 39 characters).": "Kullanıcı adı çok uzun (en fazla 39 karakter olmalı).",
|
||||||
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
"Username must have at least 2 characters": "Kullanıcı adı en az iki karakterden oluşmalı",
|
||||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Çok fazla hatalı şifre denemesi yaptınız. %d dakika kadar bekleyip yeniden giriş yapmayı deneyebilirsiniz.",
|
||||||
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
"password or code is incorrect": "password or code is incorrect",
|
"password or code is incorrect": "şifre veya kod hatalı",
|
||||||
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
"unsupported password type: %s": "unsupported password type: %s"
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
},
|
},
|
||||||
@@ -114,8 +117,8 @@
|
|||||||
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"Display name cannot be empty": "Display name cannot be empty",
|
"Display name cannot be empty": "Görünen ad boş olamaz",
|
||||||
"New password cannot contain blank space.": "New password cannot contain blank space."
|
"New password cannot contain blank space.": "Yeni şifreniz boşluk karakteri içeremez."
|
||||||
},
|
},
|
||||||
"user_upload": {
|
"user_upload": {
|
||||||
"Failed to import users": "Failed to import users"
|
"Failed to import users": "Failed to import users"
|
||||||
@@ -128,7 +131,7 @@
|
|||||||
"verification": {
|
"verification": {
|
||||||
"Code has not been sent yet!": "Code has not been sent yet!",
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
"Invalid captcha provider.": "Invalid captcha provider.",
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
"Phone number is invalid in your region %s": "Telefon numaranızın bulunduğu bölgeye hizmet veremiyoruz",
|
||||||
"Turing test failed.": "Turing test failed.",
|
"Turing test failed.": "Turing test failed.",
|
||||||
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
"The application: %s does not exist": "The application: %s does not exist",
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
"Unauthorized operation": "Unauthorized operation",
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký như một tài khoản mới, vui lòng liên hệ với bộ phận hỗ trợ công nghệ thông tin của bạn",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký như một tài khoản mới, vui lòng liên hệ với bộ phận hỗ trợ công nghệ thông tin của bạn",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) đã được liên kết với tài khoản khác: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) đã được liên kết với tài khoản khác: %s (%s)",
|
||||||
"The application: %s does not exist": "Ứng dụng: %s không tồn tại",
|
"The application: %s does not exist": "Ứng dụng: %s không tồn tại",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||||
|
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||||
"The login method: login with password is not enabled for the application": "Phương thức đăng nhập: đăng nhập bằng mật khẩu không được kích hoạt cho ứng dụng",
|
"The login method: login with password is not enabled for the application": "Phương thức đăng nhập: đăng nhập bằng mật khẩu không được kích hoạt cho ứng dụng",
|
||||||
"The provider: %s is not enabled for the application": "Nhà cung cấp: %s không được kích hoạt cho ứng dụng",
|
"The provider: %s is not enabled for the application": "Nhà cung cấp: %s không được kích hoạt cho ứng dụng",
|
||||||
"Unauthorized operation": "Hoạt động không được ủy quyền",
|
"Unauthorized operation": "Hoạt động không được ủy quyền",
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
||||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s与用户名: %s (%s)已经与其他账户绑定: %s (%s)",
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s与用户名: %s (%s)已经与其他账户绑定: %s (%s)",
|
||||||
"The application: %s does not exist": "应用%s不存在",
|
"The application: %s does not exist": "应用%s不存在",
|
||||||
|
"The login method: login with LDAP is not enabled for the application": "该应用禁止采用LDAP登录方式",
|
||||||
|
"The login method: login with SMS is not enabled for the application": "该应用禁止采用短信登录方式",
|
||||||
|
"The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式",
|
||||||
"The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
|
"The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
|
||||||
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
|
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
|
||||||
"Unauthorized operation": "未授权的操作",
|
"Unauthorized operation": "未授权的操作",
|
||||||
|
30
idp/lark.go
30
idp/lark.go
@@ -16,6 +16,7 @@ package idp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -82,13 +83,22 @@ func (idp *LarkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
AppID string `json:"app_id"`
|
AppID string `json:"app_id"`
|
||||||
AppSecret string `json:"app_secret"`
|
AppSecret string `json:"app_secret"`
|
||||||
}{idp.Config.ClientID, idp.Config.ClientSecret}
|
}{idp.Config.ClientID, idp.Config.ClientSecret}
|
||||||
|
|
||||||
data, err := idp.postWithBody(params, idp.Config.Endpoint.TokenURL)
|
data, err := idp.postWithBody(params, idp.Config.Endpoint.TokenURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
appToken := &LarkAccessToken{}
|
appToken := &LarkAccessToken{}
|
||||||
if err = json.Unmarshal(data, appToken); err != nil || appToken.Code != 0 {
|
err = json.Unmarshal(data, appToken)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if appToken.Code != 0 {
|
||||||
|
return nil, fmt.Errorf("GetToken() error, appToken.Code: %d, appToken.Msg: %s", appToken.Code, appToken.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
t := &oauth2.Token{
|
t := &oauth2.Token{
|
||||||
AccessToken: appToken.TenantAccessToken,
|
AccessToken: appToken.TenantAccessToken,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
@@ -98,7 +108,6 @@ func (idp *LarkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
raw := make(map[string]interface{})
|
raw := make(map[string]interface{})
|
||||||
raw["code"] = code
|
raw["code"] = code
|
||||||
t = t.WithExtra(raw)
|
t = t.WithExtra(raw)
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +168,17 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
GrantType string `json:"grant_type"`
|
GrantType string `json:"grant_type"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}{"authorization_code", token.Extra("code").(string)}
|
}{"authorization_code", token.Extra("code").(string)}
|
||||||
data, _ := json.Marshal(body)
|
|
||||||
|
data, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "https://open.feishu.cn/open-apis/authen/v1/access_token", strings.NewReader(string(data)))
|
req, err := http.NewRequest("POST", "https://open.feishu.cn/open-apis/authen/v1/access_token", strings.NewReader(string(data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
|
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
|
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
|
||||||
|
|
||||||
@@ -171,6 +186,7 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
data, err = io.ReadAll(resp.Body)
|
data, err = io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -178,7 +194,8 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var larkUserInfo LarkUserInfo
|
var larkUserInfo LarkUserInfo
|
||||||
if err = json.Unmarshal(data, &larkUserInfo); err != nil {
|
err = json.Unmarshal(data, &larkUserInfo)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +206,6 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
Email: larkUserInfo.Data.Email,
|
Email: larkUserInfo.Data.Email,
|
||||||
AvatarUrl: larkUserInfo.Data.AvatarUrl,
|
AvatarUrl: larkUserInfo.Data.AvatarUrl,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &userInfo, nil
|
return &userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,21 +214,23 @@ func (idp *LarkIdProvider) postWithBody(body interface{}, url string) ([]byte, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r := strings.NewReader(string(bs))
|
r := strings.NewReader(string(bs))
|
||||||
resp, err := idp.Client.Post(url, "application/json;charset=UTF-8", r)
|
resp, err := idp.Client.Post(url, "application/json;charset=UTF-8", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := io.ReadAll(resp.Body)
|
data, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(Body io.ReadCloser) {
|
defer func(Body io.ReadCloser) {
|
||||||
err := Body.Close()
|
err := Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}(resp.Body)
|
}(resp.Body)
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
@@ -119,6 +119,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) (IdProvider, error
|
|||||||
return NewMetaMaskIdProvider(), nil
|
return NewMetaMaskIdProvider(), nil
|
||||||
case "Web3Onboard":
|
case "Web3Onboard":
|
||||||
return NewWeb3OnboardIdProvider(), nil
|
return NewWeb3OnboardIdProvider(), nil
|
||||||
|
case "Twitter":
|
||||||
|
return NewTwitterIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||||
default:
|
default:
|
||||||
if isGothSupport(idpInfo.Type) {
|
if isGothSupport(idpInfo.Type) {
|
||||||
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, idpInfo.ClientId2, idpInfo.ClientSecret2, redirectUrl, idpInfo.HostUrl)
|
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, idpInfo.ClientId2, idpInfo.ClientSecret2, redirectUrl, idpInfo.HostUrl)
|
||||||
@@ -171,7 +173,6 @@ var gothList = []string{
|
|||||||
"TikTok",
|
"TikTok",
|
||||||
"Tumblr",
|
"Tumblr",
|
||||||
"Twitch",
|
"Twitch",
|
||||||
"Twitter",
|
|
||||||
"Typetalk",
|
"Typetalk",
|
||||||
"Uber",
|
"Uber",
|
||||||
"VK",
|
"VK",
|
||||||
|
190
idp/twitter.go
Normal file
190
idp/twitter.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package idp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TwitterIdProvider struct {
|
||||||
|
Client *http.Client
|
||||||
|
Config *oauth2.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTwitterIdProvider(clientId string, clientSecret string, redirectUrl string) *TwitterIdProvider {
|
||||||
|
idp := &TwitterIdProvider{}
|
||||||
|
|
||||||
|
config := idp.getConfig(clientId, clientSecret, redirectUrl)
|
||||||
|
idp.Config = config
|
||||||
|
|
||||||
|
return idp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *TwitterIdProvider) SetHttpClient(client *http.Client) {
|
||||||
|
idp.Client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||||
|
func (idp *TwitterIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||||
|
endpoint := oauth2.Endpoint{
|
||||||
|
TokenURL: "https://api.twitter.com/2/oauth2/token",
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &oauth2.Config{
|
||||||
|
Scopes: []string{"users.read", "tweet.read"},
|
||||||
|
Endpoint: endpoint,
|
||||||
|
ClientID: clientId,
|
||||||
|
ClientSecret: clientSecret,
|
||||||
|
RedirectURL: redirectUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
type TwitterAccessToken struct {
|
||||||
|
AccessToken string `json:"access_token"` // Interface call credentials
|
||||||
|
TokenType string `json:"token_type"` // Access token type
|
||||||
|
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TwitterCheckToken struct {
|
||||||
|
Data TwitterUserInfo `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwitterCheckTokenData
|
||||||
|
// Get more detail via: https://developers.Twitter.com/docs/Twitter-login/guides/advanced/manual-flow#checktoken
|
||||||
|
type TwitterCheckTokenData struct {
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||||
|
// get more detail via: https://developers.Twitter.com/docs/Twitter-login/guides/advanced/manual-flow#confirm
|
||||||
|
func (idp *TwitterIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
// params.Add("client_id", idp.Config.ClientID)
|
||||||
|
params.Add("redirect_uri", idp.Config.RedirectURL)
|
||||||
|
params.Add("code_verifier", "casdoor-verifier")
|
||||||
|
params.Add("code", code)
|
||||||
|
params.Add("grant_type", "authorization_code")
|
||||||
|
req, err := http.NewRequest("POST", "https://api.twitter.com/2/oauth2/token", strings.NewReader(params.Encode()))
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
e := base64.StdEncoding.EncodeToString([]byte(idp.Config.ClientID + ":" + idp.Config.ClientSecret))
|
||||||
|
req.Header.Add("Authorization", "Basic "+e)
|
||||||
|
accessTokenResp, err := idp.GetUrlResp(req)
|
||||||
|
var TwitterAccessToken TwitterAccessToken
|
||||||
|
if err = json.Unmarshal([]byte(accessTokenResp), &TwitterAccessToken); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := oauth2.Token{
|
||||||
|
AccessToken: TwitterAccessToken.AccessToken,
|
||||||
|
TokenType: TwitterAccessToken.TokenType,
|
||||||
|
Expiry: time.Time{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//{
|
||||||
|
// "id": "123456789",
|
||||||
|
// "name": "Example Name",
|
||||||
|
// "name_format": "{first} {last}",
|
||||||
|
// "picture": {
|
||||||
|
// "data": {
|
||||||
|
// "height": 50,
|
||||||
|
// "is_silhouette": false,
|
||||||
|
// "url": "https://example.com",
|
||||||
|
// "width": 50
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "email": "test@example.com"
|
||||||
|
//}
|
||||||
|
|
||||||
|
type TwitterUserInfo struct {
|
||||||
|
Id string `json:"id"` // The app user's App-Scoped User ID. This ID is unique to the app and cannot be used by other apps.
|
||||||
|
Name string `json:"name"` // The person's full name.
|
||||||
|
UserName string `json:"username"` // The person's name formatted to correctly handle Chinese, Japanese, or Korean ordering.
|
||||||
|
Picture struct { // The person's profile picture.
|
||||||
|
Data struct { // This struct is different as https://developers.Twitter.com/docs/graph-api/reference/user/picture/
|
||||||
|
Height int `json:"height"`
|
||||||
|
IsSilhouette bool `json:"is_silhouette"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
} `json:"data"`
|
||||||
|
} `json:"picture"`
|
||||||
|
Email string `json:"email"` // The User's primary email address listed on their profile. This field will not be returned if no valid email address is available.
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserInfo use TwitterAccessToken gotten before return TwitterUserInfo
|
||||||
|
// get more detail via: https://developers.Twitter.com/docs/graph-api/reference/user
|
||||||
|
func (idp *TwitterIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||||
|
var TwitterUserInfo TwitterUserInfo
|
||||||
|
// accessToken := token.AccessToken
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "https://api.twitter.com/2/users/me", nil)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Add("Authorization", "Bearer "+token.AccessToken)
|
||||||
|
// req.URL.Query().Set("user.fields", "profile_image_url")
|
||||||
|
// userIdUrl := fmt.Sprintf("https://graph.Twitter.com/me?access_token=%s", accessToken)
|
||||||
|
userIdResp, err := idp.GetUrlResp(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
empTwitterCheckToken := &TwitterCheckToken{}
|
||||||
|
if err = json.Unmarshal([]byte(userIdResp), &empTwitterCheckToken); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
TwitterUserInfo = empTwitterCheckToken.Data
|
||||||
|
|
||||||
|
userInfo := UserInfo{
|
||||||
|
Id: TwitterUserInfo.Id,
|
||||||
|
Username: TwitterUserInfo.UserName,
|
||||||
|
DisplayName: TwitterUserInfo.Name,
|
||||||
|
Email: TwitterUserInfo.Email,
|
||||||
|
AvatarUrl: TwitterUserInfo.Picture.Data.Url,
|
||||||
|
}
|
||||||
|
return &userInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *TwitterIdProvider) GetUrlResp(url *http.Request) (string, error) {
|
||||||
|
resp, err := idp.Client.Do(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
err := Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err = buf.ReadFrom(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
@@ -45,6 +45,23 @@
|
|||||||
"alertType": "None"
|
"alertType": "None"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"signinMethods": [
|
||||||
|
{
|
||||||
|
"name": "Password",
|
||||||
|
"displayName": "Password",
|
||||||
|
"rule": "All",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Verification code",
|
||||||
|
"displayName": "Verification code",
|
||||||
|
"rule": "All",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WebAuthn",
|
||||||
|
"displayName": "WebAuthn",
|
||||||
|
"rule": "None",
|
||||||
|
},
|
||||||
|
],
|
||||||
"signupItems": [
|
"signupItems": [
|
||||||
{
|
{
|
||||||
"name": "ID",
|
"name": "ID",
|
||||||
@@ -106,7 +123,7 @@
|
|||||||
"redirectUris": [""],
|
"redirectUris": [""],
|
||||||
"expireInHours": 168,
|
"expireInHours": 168,
|
||||||
"failedSigninLimit": 5,
|
"failedSigninLimit": 5,
|
||||||
"failedSigninfrozenTime": 15
|
"failedSigninFrozenTime": 15
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"users": [
|
"users": [
|
||||||
|
@@ -1,23 +0,0 @@
|
|||||||
# Patterns to ignore when building packages.
|
|
||||||
# This supports shell glob matching, relative path matching, and
|
|
||||||
# negation (prefixed with !). Only one pattern per line.
|
|
||||||
.DS_Store
|
|
||||||
# Common VCS dirs
|
|
||||||
.git/
|
|
||||||
.gitignore
|
|
||||||
.bzr/
|
|
||||||
.bzrignore
|
|
||||||
.hg/
|
|
||||||
.hgignore
|
|
||||||
.svn/
|
|
||||||
# Common backup files
|
|
||||||
*.swp
|
|
||||||
*.bak
|
|
||||||
*.tmp
|
|
||||||
*.orig
|
|
||||||
*~
|
|
||||||
# Various IDEs
|
|
||||||
.project
|
|
||||||
.idea/
|
|
||||||
*.tmproj
|
|
||||||
.vscode/
|
|
@@ -1,24 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: casdoor-helm-charts
|
|
||||||
description: A Helm chart for Kubernetes
|
|
||||||
|
|
||||||
# A chart can be either an 'application' or a 'library' chart.
|
|
||||||
#
|
|
||||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
|
||||||
# to be deployed.
|
|
||||||
#
|
|
||||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
|
||||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
|
||||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
|
||||||
type: application
|
|
||||||
|
|
||||||
# This is the chart version. This version number should be incremented each time you make changes
|
|
||||||
# to the chart and its templates, including the app version.
|
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
|
||||||
version: 0.3.0
|
|
||||||
|
|
||||||
# This is the version number of the application being deployed. This version number should be
|
|
||||||
# incremented each time you make changes to the application. Versions are not expected to
|
|
||||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
|
||||||
# It is recommended to use it with quotes.
|
|
||||||
appVersion: "1.18.0"
|
|
@@ -1,22 +0,0 @@
|
|||||||
1. Get the application URL by running these commands:
|
|
||||||
{{- if .Values.ingress.enabled }}
|
|
||||||
{{- range $host := .Values.ingress.hosts }}
|
|
||||||
{{- range .paths }}
|
|
||||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- else if contains "NodePort" .Values.service.type }}
|
|
||||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "casdoor.fullname" . }})
|
|
||||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
|
||||||
echo http://$NODE_IP:$NODE_PORT
|
|
||||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
|
||||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
|
||||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "casdoor.fullname" . }}'
|
|
||||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "casdoor.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
|
||||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
|
||||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
|
||||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "casdoor.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
|
||||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
|
||||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
|
||||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
|
||||||
{{- end }}
|
|
@@ -1,62 +0,0 @@
|
|||||||
{{/*
|
|
||||||
Expand the name of the chart.
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.name" -}}
|
|
||||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create a default fully qualified app name.
|
|
||||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
|
||||||
If release name contains chart name it will be used as a full name.
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.fullname" -}}
|
|
||||||
{{- if .Values.fullnameOverride }}
|
|
||||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
|
||||||
{{- if contains $name .Release.Name }}
|
|
||||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- else }}
|
|
||||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create chart name and version as used by the chart label.
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Common labels
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.labels" -}}
|
|
||||||
helm.sh/chart: {{ include "casdoor.chart" . }}
|
|
||||||
{{ include "casdoor.selectorLabels" . }}
|
|
||||||
{{- if .Chart.AppVersion }}
|
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Selector labels
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ include "casdoor.name" . }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create the name of the service account to use
|
|
||||||
*/}}
|
|
||||||
{{- define "casdoor.serviceAccountName" -}}
|
|
||||||
{{- if .Values.serviceAccount.create }}
|
|
||||||
{{- default (include "casdoor.fullname" .) .Values.serviceAccount.name }}
|
|
||||||
{{- else }}
|
|
||||||
{{- default "default" .Values.serviceAccount.name }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
@@ -1,8 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ printf "%s-config" (include "casdoor.fullname" .) }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
data:
|
|
||||||
app.conf: {{ tpl .Values.config . | toYaml | nindent 4 }}
|
|
@@ -1,86 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ include "casdoor.fullname" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not .Values.autoscaling.enabled }}
|
|
||||||
replicas: {{ .Values.replicaCount }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "casdoor.selectorLabels" . | nindent 6 }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
checksum/config: {{ tpl .Values.config . | toYaml | sha256sum }}
|
|
||||||
{{- with .Values.podAnnotations }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.selectorLabels" . | nindent 8 }}
|
|
||||||
spec:
|
|
||||||
{{- with .Values.imagePullSecrets }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
serviceAccountName: {{ include "casdoor.serviceAccountName" . }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
|
||||||
containers:
|
|
||||||
- name: {{ .Chart.Name }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
|
||||||
image: "{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
|
||||||
# command: ["sleep", "100000000"]
|
|
||||||
env:
|
|
||||||
- name: RUNNING_IN_DOCKER
|
|
||||||
value: "true"
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: {{ .Values.service.port }}
|
|
||||||
protocol: TCP
|
|
||||||
{{ if .Values.probe.liveness.enabled }}
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: http
|
|
||||||
{{ end }}
|
|
||||||
{{ if .Values.probe.readiness.enabled }}
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: http
|
|
||||||
{{ end }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
|
||||||
volumeMounts:
|
|
||||||
- name: config-volume
|
|
||||||
mountPath: /conf
|
|
||||||
{{ if .Values.extraContainersEnabled }}
|
|
||||||
{{- .Values.extraContainers | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
volumes:
|
|
||||||
- name: config-volume
|
|
||||||
projected:
|
|
||||||
defaultMode: 420
|
|
||||||
sources:
|
|
||||||
- configMap:
|
|
||||||
items:
|
|
||||||
- key: app.conf
|
|
||||||
path: app.conf
|
|
||||||
name: {{ printf "%s-config" (include "casdoor.fullname" .) }}
|
|
||||||
{{- with .Values.nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.affinity }}
|
|
||||||
affinity:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
@@ -1,28 +0,0 @@
|
|||||||
{{- if .Values.autoscaling.enabled }}
|
|
||||||
apiVersion: autoscaling/v2beta1
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ include "casdoor.fullname" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ include "casdoor.fullname" . }}
|
|
||||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
|
||||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
|
||||||
metrics:
|
|
||||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: memory
|
|
||||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
@@ -1,61 +0,0 @@
|
|||||||
{{- if .Values.ingress.enabled -}}
|
|
||||||
{{- $fullName := include "casdoor.fullname" . -}}
|
|
||||||
{{- $svcPort := .Values.service.port -}}
|
|
||||||
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
|
||||||
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
|
||||||
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
{{- end }}
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: {{ $fullName }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.ingress.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: {{ .Values.ingress.className }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.ingress.tls }}
|
|
||||||
tls:
|
|
||||||
{{- range .Values.ingress.tls }}
|
|
||||||
- hosts:
|
|
||||||
{{- range .hosts }}
|
|
||||||
- {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
secretName: {{ .secretName }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
{{- range .Values.ingress.hosts }}
|
|
||||||
- host: {{ .host | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
{{- range .paths }}
|
|
||||||
- path: {{ .path }}
|
|
||||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
pathType: {{ .pathType }}
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: {{ $fullName }}
|
|
||||||
port:
|
|
||||||
number: {{ $svcPort }}
|
|
||||||
{{- else }}
|
|
||||||
serviceName: {{ $fullName }}
|
|
||||||
servicePort: {{ $svcPort }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
@@ -1,15 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ include "casdoor.fullname" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: {{ .Values.service.type }}
|
|
||||||
ports:
|
|
||||||
- port: {{ .Values.service.port }}
|
|
||||||
targetPort: http
|
|
||||||
protocol: TCP
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
{{- include "casdoor.selectorLabels" . | nindent 4 }}
|
|
@@ -1,12 +0,0 @@
|
|||||||
{{- if .Values.serviceAccount.create -}}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: {{ include "casdoor.serviceAccountName" . }}
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
{{- with .Values.serviceAccount.annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
@@ -1,15 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: "{{ include "casdoor.fullname" . }}-test-connection"
|
|
||||||
labels:
|
|
||||||
{{- include "casdoor.labels" . | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
"helm.sh/hook": test
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: wget
|
|
||||||
image: busybox
|
|
||||||
command: ['wget']
|
|
||||||
args: ['{{ include "casdoor.fullname" . }}:{{ .Values.service.port }}']
|
|
||||||
restartPolicy: Never
|
|
@@ -1,117 +0,0 @@
|
|||||||
# Default values for casdoor.
|
|
||||||
# This is a YAML-formatted file.
|
|
||||||
# Declare variables to be passed into your templates.
|
|
||||||
|
|
||||||
replicaCount: 1
|
|
||||||
|
|
||||||
image:
|
|
||||||
repository: casbin
|
|
||||||
name: casdoor
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
# Overrides the image tag whose default is the chart appVersion.
|
|
||||||
tag: ""
|
|
||||||
|
|
||||||
# ref: https://casdoor.org/docs/basic/server-installation#via-ini-file
|
|
||||||
config: |
|
|
||||||
appname = casdoor
|
|
||||||
httpport = {{ .Values.service.port }}
|
|
||||||
runmode = dev
|
|
||||||
SessionOn = true
|
|
||||||
copyrequestbody = true
|
|
||||||
driverName = sqlite
|
|
||||||
dataSourceName = "file:ent?mode=memory&cache=shared&_fk=1"
|
|
||||||
dbName = casdoor
|
|
||||||
redisEndpoint =
|
|
||||||
defaultStorageProvider =
|
|
||||||
isCloudIntranet = false
|
|
||||||
authState = "casdoor"
|
|
||||||
socks5Proxy = ""
|
|
||||||
verificationCodeTimeout = 10
|
|
||||||
initScore = 0
|
|
||||||
logPostOnly = true
|
|
||||||
origin =
|
|
||||||
enableGzip = true
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
nameOverride: ""
|
|
||||||
fullnameOverride: ""
|
|
||||||
|
|
||||||
serviceAccount:
|
|
||||||
# Specifies whether a service account should be created
|
|
||||||
create: true
|
|
||||||
# Annotations to add to the service account
|
|
||||||
annotations: {}
|
|
||||||
# The name of the service account to use.
|
|
||||||
# If not set and create is true, a name is generated using the fullname template
|
|
||||||
name: ""
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext: {}
|
|
||||||
# fsGroup: 2000
|
|
||||||
|
|
||||||
securityContext: {}
|
|
||||||
# capabilities:
|
|
||||||
# drop:
|
|
||||||
# - ALL
|
|
||||||
# readOnlyRootFilesystem: true
|
|
||||||
# runAsNonRoot: true
|
|
||||||
# runAsUser: 1000
|
|
||||||
|
|
||||||
probe:
|
|
||||||
readiness:
|
|
||||||
enabled: true
|
|
||||||
liveness:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
service:
|
|
||||||
type: ClusterIP
|
|
||||||
port: 8000
|
|
||||||
|
|
||||||
ingress:
|
|
||||||
enabled: false
|
|
||||||
className: ""
|
|
||||||
annotations: {}
|
|
||||||
# kubernetes.io/ingress.class: nginx
|
|
||||||
# kubernetes.io/tls-acme: "true"
|
|
||||||
hosts:
|
|
||||||
- host: chart-example.local
|
|
||||||
paths:
|
|
||||||
- path: /
|
|
||||||
pathType: ImplementationSpecific
|
|
||||||
tls: []
|
|
||||||
# - secretName: chart-example-tls
|
|
||||||
# hosts:
|
|
||||||
# - chart-example.local
|
|
||||||
|
|
||||||
resources: {}
|
|
||||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
|
||||||
# choice for the user. This also increases chances charts run on environments with little
|
|
||||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
|
||||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
|
||||||
# limits:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
# requests:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
|
|
||||||
autoscaling:
|
|
||||||
enabled: false
|
|
||||||
minReplicas: 1
|
|
||||||
maxReplicas: 100
|
|
||||||
targetCPUUtilizationPercentage: 80
|
|
||||||
# targetMemoryUtilizationPercentage: 80
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
# -- Optionally add extra sidecar containers.
|
|
||||||
extraContainersEnabled: false
|
|
||||||
extraContainers: ""
|
|
||||||
# extraContainers: |
|
|
||||||
# - name: ...
|
|
||||||
# image: ...
|
|
@@ -24,6 +24,12 @@ import (
|
|||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SigninMethod struct {
|
||||||
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
Rule string `json:"rule"`
|
||||||
|
}
|
||||||
|
|
||||||
type SignupItem struct {
|
type SignupItem struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Visible bool `json:"visible"`
|
Visible bool `json:"visible"`
|
||||||
@@ -31,12 +37,13 @@ type SignupItem struct {
|
|||||||
Prompted bool `json:"prompted"`
|
Prompted bool `json:"prompted"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Placeholder string `json:"placeholder"`
|
Placeholder string `json:"placeholder"`
|
||||||
|
Regex string `json:"regex"`
|
||||||
Rule string `json:"rule"`
|
Rule string `json:"rule"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SamlItem struct {
|
type SamlItem struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
NameFormat string `json:"nameformat"`
|
NameFormat string `json:"nameFormat"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,18 +70,19 @@ type Application struct {
|
|||||||
OrgChoiceMode string `json:"orgChoiceMode"`
|
OrgChoiceMode string `json:"orgChoiceMode"`
|
||||||
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
||||||
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
||||||
|
SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"`
|
||||||
SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
|
SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
|
||||||
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
|
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
|
||||||
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
|
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
|
||||||
CertPublicKey string `xorm:"-" json:"certPublicKey"`
|
CertPublicKey string `xorm:"-" json:"certPublicKey"`
|
||||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||||
InvitationCodes []string `xorm:"varchar(200)" json:"invitationCodes"`
|
|
||||||
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
|
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
|
||||||
|
|
||||||
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
||||||
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
|
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
|
||||||
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
|
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
|
||||||
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
|
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
|
||||||
|
TokenFields []string `xorm:"varchar(1000)" json:"tokenFields"`
|
||||||
ExpireInHours int `json:"expireInHours"`
|
ExpireInHours int `json:"expireInHours"`
|
||||||
RefreshExpireInHours int `json:"refreshExpireInHours"`
|
RefreshExpireInHours int `json:"refreshExpireInHours"`
|
||||||
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
|
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
|
||||||
@@ -92,7 +100,7 @@ type Application struct {
|
|||||||
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
|
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
|
||||||
|
|
||||||
FailedSigninLimit int `json:"failedSigninLimit"`
|
FailedSigninLimit int `json:"failedSigninLimit"`
|
||||||
FailedSigninfrozenTime int `json:"failedSigninfrozenTime"`
|
FailedSigninFrozenTime int `json:"failedSigninFrozenTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetApplicationCount(owner, field, value string) (int64, error) {
|
func GetApplicationCount(owner, field, value string) (int64, error) {
|
||||||
@@ -191,6 +199,30 @@ func extendApplicationWithOrg(application *Application) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extendApplicationWithSigninMethods(application *Application) (err error) {
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
if application.EnablePassword {
|
||||||
|
signinMethod := &SigninMethod{Name: "Password", DisplayName: "Password", Rule: "All"}
|
||||||
|
application.SigninMethods = append(application.SigninMethods, signinMethod)
|
||||||
|
}
|
||||||
|
if application.EnableCodeSignin {
|
||||||
|
signinMethod := &SigninMethod{Name: "Verification code", DisplayName: "Verification code", Rule: "All"}
|
||||||
|
application.SigninMethods = append(application.SigninMethods, signinMethod)
|
||||||
|
}
|
||||||
|
if application.EnableWebAuthn {
|
||||||
|
signinMethod := &SigninMethod{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"}
|
||||||
|
application.SigninMethods = append(application.SigninMethods, signinMethod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
signinMethod := &SigninMethod{Name: "Password", DisplayName: "Password", Rule: "All"}
|
||||||
|
application.SigninMethods = append(application.SigninMethods, signinMethod)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func getApplication(owner string, name string) (*Application, error) {
|
func getApplication(owner string, name string) (*Application, error) {
|
||||||
if owner == "" || name == "" {
|
if owner == "" || name == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -213,6 +245,11 @@ func getApplication(owner string, name string) (*Application, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = extendApplicationWithSigninMethods(&application)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &application, nil
|
return &application, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -237,6 +274,11 @@ func GetApplicationByOrganizationName(organization string) (*Application, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = extendApplicationWithSigninMethods(&application)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &application, nil
|
return &application, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -284,6 +326,11 @@ func GetApplicationByClientId(clientId string) (*Application, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = extendApplicationWithSigninMethods(&application)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &application, nil
|
return &application, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -300,6 +347,17 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if application.TokenFields == nil {
|
||||||
|
application.TokenFields = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if application.FailedSigninLimit == 0 {
|
||||||
|
application.FailedSigninLimit = DefaultFailedSigninLimit
|
||||||
|
}
|
||||||
|
if application.FailedSigninFrozenTime == 0 {
|
||||||
|
application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime
|
||||||
|
}
|
||||||
|
|
||||||
if userId != "" {
|
if userId != "" {
|
||||||
if isUserIdGlobalAdmin(userId) {
|
if isUserIdGlobalAdmin(userId) {
|
||||||
return application
|
return application
|
||||||
@@ -333,10 +391,6 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.InvitationCodes != nil {
|
|
||||||
application.InvitationCodes = []string{"***"}
|
|
||||||
}
|
|
||||||
|
|
||||||
return application
|
return application
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,6 +539,69 @@ func (application *Application) IsRedirectUriValid(redirectUri string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (application *Application) IsPasswordEnabled() bool {
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
return application.EnablePassword
|
||||||
|
} else {
|
||||||
|
for _, signinMethod := range application.SigninMethods {
|
||||||
|
if signinMethod.Name == "Password" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (application *Application) IsPasswordWithLdapEnabled() bool {
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
return application.EnablePassword
|
||||||
|
} else {
|
||||||
|
for _, signinMethod := range application.SigninMethods {
|
||||||
|
if signinMethod.Name == "Password" && signinMethod.Rule == "All" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (application *Application) IsCodeSigninViaEmailEnabled() bool {
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
return application.EnableCodeSignin
|
||||||
|
} else {
|
||||||
|
for _, signinMethod := range application.SigninMethods {
|
||||||
|
if signinMethod.Name == "Verification code" && signinMethod.Rule != "Phone only" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (application *Application) IsCodeSigninViaSmsEnabled() bool {
|
||||||
|
if len(application.SigninMethods) == 0 {
|
||||||
|
return application.EnableCodeSignin
|
||||||
|
} else {
|
||||||
|
for _, signinMethod := range application.SigninMethods {
|
||||||
|
if signinMethod.Name == "Verification code" && signinMethod.Rule != "Email only" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (application *Application) IsLdapEnabled() bool {
|
||||||
|
if len(application.SigninMethods) > 0 {
|
||||||
|
for _, signinMethod := range application.SigninMethods {
|
||||||
|
if signinMethod.Name == "LDAP" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func IsOriginAllowed(origin string) (bool, error) {
|
func IsOriginAllowed(origin string) (bool, error) {
|
||||||
applications, err := GetApplications("")
|
applications, err := GetApplications("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -579,7 +696,7 @@ func applicationChangeTrigger(oldName string, newName string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
permissions[i].Resources = permissionResoureces
|
permissions[i].Resources = permissionResoureces
|
||||||
_, err = session.Where("name=?", permissions[i].Name).Update(permissions[i])
|
_, err = session.Where("owner=?", permissions[i].Owner).Where("name=?", permissions[i].Name).Update(permissions[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
117
object/check.go
117
object/check.go
@@ -16,6 +16,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
@@ -28,94 +29,93 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultFailedSigninLimit = 5
|
DefaultFailedSigninLimit = 5
|
||||||
// DefaultFailedSigninfrozenTime The unit of frozen time is minutes
|
DefaultFailedSigninFrozenTime = 15
|
||||||
DefaultFailedSigninfrozenTime = 15
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckUserSignup(application *Application, organization *Organization, form *form.AuthForm, lang string) string {
|
func CheckUserSignup(application *Application, organization *Organization, authForm *form.AuthForm, lang string) string {
|
||||||
if organization == nil {
|
if organization == nil {
|
||||||
return i18n.Translate(lang, "check:Organization does not exist")
|
return i18n.Translate(lang, "check:Organization does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Username") {
|
if application.IsSignupItemVisible("Username") {
|
||||||
if len(form.Username) <= 1 {
|
if len(authForm.Username) <= 1 {
|
||||||
return i18n.Translate(lang, "check:Username must have at least 2 characters")
|
return i18n.Translate(lang, "check:Username must have at least 2 characters")
|
||||||
}
|
}
|
||||||
if unicode.IsDigit(rune(form.Username[0])) {
|
if unicode.IsDigit(rune(authForm.Username[0])) {
|
||||||
return i18n.Translate(lang, "check:Username cannot start with a digit")
|
return i18n.Translate(lang, "check:Username cannot start with a digit")
|
||||||
}
|
}
|
||||||
if util.IsEmailValid(form.Username) {
|
if util.IsEmailValid(authForm.Username) {
|
||||||
return i18n.Translate(lang, "check:Username cannot be an email address")
|
return i18n.Translate(lang, "check:Username cannot be an email address")
|
||||||
}
|
}
|
||||||
if util.ReWhiteSpace.MatchString(form.Username) {
|
if util.ReWhiteSpace.MatchString(authForm.Username) {
|
||||||
return i18n.Translate(lang, "check:Username cannot contain white spaces")
|
return i18n.Translate(lang, "check:Username cannot contain white spaces")
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg := CheckUsername(form.Username, lang); msg != "" {
|
if msg := CheckUsername(authForm.Username, lang); msg != "" {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
if HasUserByField(organization.Name, "name", form.Username) {
|
if HasUserByField(organization.Name, "name", authForm.Username) {
|
||||||
return i18n.Translate(lang, "check:Username already exists")
|
return i18n.Translate(lang, "check:Username already exists")
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "email", form.Email) {
|
if HasUserByField(organization.Name, "email", authForm.Email) {
|
||||||
return i18n.Translate(lang, "check:Email already exists")
|
return i18n.Translate(lang, "check:Email already exists")
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "phone", form.Phone) {
|
if HasUserByField(organization.Name, "phone", authForm.Phone) {
|
||||||
return i18n.Translate(lang, "check:Phone already exists")
|
return i18n.Translate(lang, "check:Phone already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Password") {
|
if application.IsSignupItemVisible("Password") {
|
||||||
msg := CheckPasswordComplexityByOrg(organization, form.Password)
|
msg := CheckPasswordComplexityByOrg(organization, authForm.Password)
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Email") {
|
if application.IsSignupItemVisible("Email") {
|
||||||
if form.Email == "" {
|
if authForm.Email == "" {
|
||||||
if application.IsSignupItemRequired("Email") {
|
if application.IsSignupItemRequired("Email") {
|
||||||
return i18n.Translate(lang, "check:Email cannot be empty")
|
return i18n.Translate(lang, "check:Email cannot be empty")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if HasUserByField(organization.Name, "email", form.Email) {
|
if HasUserByField(organization.Name, "email", authForm.Email) {
|
||||||
return i18n.Translate(lang, "check:Email already exists")
|
return i18n.Translate(lang, "check:Email already exists")
|
||||||
} else if !util.IsEmailValid(form.Email) {
|
} else if !util.IsEmailValid(authForm.Email) {
|
||||||
return i18n.Translate(lang, "check:Email is invalid")
|
return i18n.Translate(lang, "check:Email is invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Phone") {
|
if application.IsSignupItemVisible("Phone") {
|
||||||
if form.Phone == "" {
|
if authForm.Phone == "" {
|
||||||
if application.IsSignupItemRequired("Phone") {
|
if application.IsSignupItemRequired("Phone") {
|
||||||
return i18n.Translate(lang, "check:Phone cannot be empty")
|
return i18n.Translate(lang, "check:Phone cannot be empty")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if HasUserByField(organization.Name, "phone", form.Phone) {
|
if HasUserByField(organization.Name, "phone", authForm.Phone) {
|
||||||
return i18n.Translate(lang, "check:Phone already exists")
|
return i18n.Translate(lang, "check:Phone already exists")
|
||||||
} else if !util.IsPhoneAllowInRegin(form.CountryCode, organization.CountryCodes) {
|
} else if !util.IsPhoneAllowInRegin(authForm.CountryCode, organization.CountryCodes) {
|
||||||
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
|
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
|
||||||
} else if !util.IsPhoneValid(form.Phone, form.CountryCode) {
|
} else if !util.IsPhoneValid(authForm.Phone, authForm.CountryCode) {
|
||||||
return i18n.Translate(lang, "check:Phone number is invalid")
|
return i18n.Translate(lang, "check:Phone number is invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Display name") {
|
if application.IsSignupItemVisible("Display name") {
|
||||||
if application.GetSignupItemRule("Display name") == "First, last" && (form.FirstName != "" || form.LastName != "") {
|
if application.GetSignupItemRule("Display name") == "First, last" && (authForm.FirstName != "" || authForm.LastName != "") {
|
||||||
if form.FirstName == "" {
|
if authForm.FirstName == "" {
|
||||||
return i18n.Translate(lang, "check:FirstName cannot be blank")
|
return i18n.Translate(lang, "check:FirstName cannot be blank")
|
||||||
} else if form.LastName == "" {
|
} else if authForm.LastName == "" {
|
||||||
return i18n.Translate(lang, "check:LastName cannot be blank")
|
return i18n.Translate(lang, "check:LastName cannot be blank")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if form.Name == "" {
|
if authForm.Name == "" {
|
||||||
return i18n.Translate(lang, "check:DisplayName cannot be blank")
|
return i18n.Translate(lang, "check:DisplayName cannot be blank")
|
||||||
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
||||||
if !isValidRealName(form.Name) {
|
if !isValidRealName(authForm.Name) {
|
||||||
return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,20 +123,29 @@ func CheckUserSignup(application *Application, organization *Organization, form
|
|||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Affiliation") {
|
if application.IsSignupItemVisible("Affiliation") {
|
||||||
if form.Affiliation == "" {
|
if authForm.Affiliation == "" {
|
||||||
return i18n.Translate(lang, "check:Affiliation cannot be blank")
|
return i18n.Translate(lang, "check:Affiliation cannot be blank")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(application.InvitationCodes) > 0 {
|
for _, signupItem := range application.SignupItems {
|
||||||
if form.InvitationCode == "" {
|
if signupItem.Regex == "" {
|
||||||
if application.IsSignupItemRequired("Invitation code") {
|
continue
|
||||||
return i18n.Translate(lang, "check:Invitation code cannot be blank")
|
}
|
||||||
}
|
|
||||||
} else {
|
isString, value := form.GetAuthFormFieldValue(authForm, signupItem.Name)
|
||||||
if !util.InSlice(application.InvitationCodes, form.InvitationCode) {
|
if !isString {
|
||||||
return i18n.Translate(lang, "check:Invitation code is invalid")
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regexSignupItem, err := regexp.Compile(signupItem.Regex)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
matched := regexSignupItem.MatchString(value)
|
||||||
|
if !matched {
|
||||||
|
return fmt.Sprintf(i18n.Translate(lang, "check:The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\""), value, signupItem.Name, application.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +153,7 @@ func CheckUserSignup(application *Application, organization *Organization, form
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkSigninErrorTimes(user *User, lang string) error {
|
func checkSigninErrorTimes(user *User, lang string) error {
|
||||||
failedSigninLimit, failedSigninfrozenTime, err := GetFailedSigninConfigByUser(user)
|
failedSigninLimit, failedSigninFrozenTime, err := GetFailedSigninConfigByUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -152,7 +161,7 @@ func checkSigninErrorTimes(user *User, lang string) error {
|
|||||||
if user.SigninWrongTimes >= failedSigninLimit {
|
if user.SigninWrongTimes >= failedSigninLimit {
|
||||||
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
|
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
|
||||||
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
|
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
|
||||||
minutes := failedSigninfrozenTime - int(passedTime.Minutes())
|
minutes := failedSigninFrozenTime - int(passedTime.Minutes())
|
||||||
|
|
||||||
// deny the login if the error times is greater than the limit and the last login time is less than the duration
|
// deny the login if the error times is greater than the limit and the last login time is less than the duration
|
||||||
if minutes > 0 {
|
if minutes > 0 {
|
||||||
@@ -278,8 +287,12 @@ func checkLdapUserPassword(user *User, password string, lang string) error {
|
|||||||
|
|
||||||
func CheckUserPassword(organization string, username string, password string, lang string, options ...bool) (*User, error) {
|
func CheckUserPassword(organization string, username string, password string, lang string, options ...bool) (*User, error) {
|
||||||
enableCaptcha := false
|
enableCaptcha := false
|
||||||
|
isSigninViaLdap := false
|
||||||
|
isPasswordWithLdapEnabled := false
|
||||||
if len(options) > 0 {
|
if len(options) > 0 {
|
||||||
enableCaptcha = options[0]
|
enableCaptcha = options[0]
|
||||||
|
isSigninViaLdap = options[1]
|
||||||
|
isPasswordWithLdapEnabled = options[2]
|
||||||
}
|
}
|
||||||
user, err := GetUserByFields(organization, username)
|
user, err := GetUserByFields(organization, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -294,14 +307,33 @@ func CheckUserPassword(organization string, username string, password string, la
|
|||||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user is forbidden to sign in, please contact the administrator"))
|
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user is forbidden to sign in, please contact the administrator"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isSigninViaLdap {
|
||||||
|
if user.Ldap == "" {
|
||||||
|
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if user.Ldap != "" {
|
if user.Ldap != "" {
|
||||||
|
if !isSigninViaLdap && !isPasswordWithLdapEnabled {
|
||||||
|
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
|
// only for LDAP users
|
||||||
err = checkLdapUserPassword(user, password, lang)
|
err = checkLdapUserPassword(user, password, lang)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "user not exist" {
|
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, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username)
|
||||||
}
|
}
|
||||||
return nil, err
|
|
||||||
|
return nil, recordSigninErrorInfo(user, lang, enableCaptcha)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = CheckPassword(user, password, lang, enableCaptcha)
|
err = CheckPassword(user, password, lang, enableCaptcha)
|
||||||
@@ -486,12 +518,11 @@ func CheckToEnableCaptcha(application *Application, organization, username strin
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var failedSigninLimit int
|
failedSigninLimit := application.FailedSigninLimit
|
||||||
if application.FailedSigninLimit == 0 {
|
if failedSigninLimit == 0 {
|
||||||
failedSigninLimit = 5
|
failedSigninLimit = DefaultFailedSigninLimit
|
||||||
} else {
|
|
||||||
failedSigninLimit = application.FailedSigninLimit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return user != nil && user.SigninWrongTimes >= failedSigninLimit, nil
|
return user != nil && user.SigninWrongTimes >= failedSigninLimit, nil
|
||||||
}
|
}
|
||||||
return providerItem.Rule == "Always", nil
|
return providerItem.Rule == "Always", nil
|
||||||
|
@@ -24,7 +24,7 @@ var (
|
|||||||
regexLowerCase = regexp.MustCompile(`[a-z]`)
|
regexLowerCase = regexp.MustCompile(`[a-z]`)
|
||||||
regexUpperCase = regexp.MustCompile(`[A-Z]`)
|
regexUpperCase = regexp.MustCompile(`[A-Z]`)
|
||||||
regexDigit = regexp.MustCompile(`\d`)
|
regexDigit = regexp.MustCompile(`\d`)
|
||||||
regexSpecial = regexp.MustCompile(`[!@#$%^&*]`)
|
regexSpecial = regexp.MustCompile("[!-/:-@[-`{-~]")
|
||||||
)
|
)
|
||||||
|
|
||||||
func isValidOption_AtLeast6(password string) string {
|
func isValidOption_AtLeast6(password string) string {
|
||||||
|
@@ -52,18 +52,18 @@ func GetFailedSigninConfigByUser(user *User) (int, int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
failedSigninLimit := application.FailedSigninLimit
|
|
||||||
failedSigninfrozenTime := application.FailedSigninfrozenTime
|
|
||||||
|
|
||||||
// 0 as an initialization value, corresponding to the default configuration parameters
|
failedSigninLimit := application.FailedSigninLimit
|
||||||
if failedSigninLimit == 0 {
|
if failedSigninLimit == 0 {
|
||||||
failedSigninLimit = DefaultFailedSigninLimit
|
failedSigninLimit = DefaultFailedSigninLimit
|
||||||
}
|
}
|
||||||
if failedSigninfrozenTime == 0 {
|
|
||||||
failedSigninfrozenTime = DefaultFailedSigninfrozenTime
|
failedSigninFrozenTime := application.FailedSigninFrozenTime
|
||||||
|
if failedSigninFrozenTime == 0 {
|
||||||
|
failedSigninFrozenTime = DefaultFailedSigninFrozenTime
|
||||||
}
|
}
|
||||||
|
|
||||||
return failedSigninLimit, failedSigninfrozenTime, nil
|
return failedSigninLimit, failedSigninFrozenTime, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
|
func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
|
||||||
@@ -72,7 +72,7 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
|
|||||||
enableCaptcha = options[0]
|
enableCaptcha = options[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
failedSigninLimit, failedSigninfrozenTime, errSignin := GetFailedSigninConfigByUser(user)
|
failedSigninLimit, failedSigninFrozenTime, errSignin := GetFailedSigninConfigByUser(user)
|
||||||
if errSignin != nil {
|
if errSignin != nil {
|
||||||
return errSignin
|
return errSignin
|
||||||
}
|
}
|
||||||
@@ -101,5 +101,5 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't show the chance error message if the user has no chance left
|
// don't show the chance error message if the user has no chance left
|
||||||
return fmt.Errorf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), failedSigninfrozenTime)
|
return fmt.Errorf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), failedSigninFrozenTime)
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/builder"
|
"github.com/xorm-io/builder"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
@@ -224,7 +225,8 @@ func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
|||||||
if field == "" && value == "" {
|
if field == "" && value == "" {
|
||||||
return int64(len(names)), nil
|
return int64(len(names)), nil
|
||||||
} else {
|
} else {
|
||||||
return ormer.Engine.Table("user").
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
|
return ormer.Engine.Table(tableNamePrefix+"user").
|
||||||
Where("owner = ?", owner).In("name", names).
|
Where("owner = ?", owner).In("name", names).
|
||||||
And(fmt.Sprintf("user.%s like ?", util.CamelToSnakeCase(field)), "%"+value+"%").
|
And(fmt.Sprintf("user.%s like ?", util.CamelToSnakeCase(field)), "%"+value+"%").
|
||||||
Count()
|
Count()
|
||||||
@@ -239,7 +241,9 @@ func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, so
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
session := ormer.Engine.Table("user").
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
|
prefixedUserTable := tableNamePrefix + "user"
|
||||||
|
session := ormer.Engine.Table(prefixedUserTable).
|
||||||
Where("owner = ?", owner).In("name", names)
|
Where("owner = ?", owner).In("name", names)
|
||||||
|
|
||||||
if offset != -1 && limit != -1 {
|
if offset != -1 && limit != -1 {
|
||||||
@@ -247,16 +251,19 @@ func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, so
|
|||||||
}
|
}
|
||||||
|
|
||||||
if field != "" && value != "" {
|
if field != "" && value != "" {
|
||||||
session = session.And(fmt.Sprintf("user.%s like ?", util.CamelToSnakeCase(field)), "%"+value+"%")
|
session = session.And(fmt.Sprintf("%s.%s like ?", prefixedUserTable, util.CamelToSnakeCase(field)), "%"+value+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
if sortField == "" || sortOrder == "" {
|
if sortField == "" || sortOrder == "" {
|
||||||
sortField = "created_time"
|
sortField = "created_time"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orderQuery := fmt.Sprintf("%s.%s", prefixedUserTable, util.SnakeString(sortField))
|
||||||
|
|
||||||
if sortOrder == "ascend" {
|
if sortOrder == "ascend" {
|
||||||
session = session.Asc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
session = session.Asc(orderQuery)
|
||||||
} else {
|
} else {
|
||||||
session = session.Desc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
session = session.Desc(orderQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = session.Find(&users)
|
err = session.Find(&users)
|
||||||
|
@@ -180,6 +180,11 @@ func initBuiltInApplication() {
|
|||||||
Providers: []*ProviderItem{
|
Providers: []*ProviderItem{
|
||||||
{Name: "provider_captcha_default", CanSignUp: false, CanSignIn: false, CanUnlink: false, Prompted: false, SignupGroup: "", Rule: "None", Provider: nil},
|
{Name: "provider_captcha_default", CanSignUp: false, CanSignIn: false, CanUnlink: false, Prompted: false, SignupGroup: "", Rule: "None", Provider: nil},
|
||||||
},
|
},
|
||||||
|
SigninMethods: []*SigninMethod{
|
||||||
|
{Name: "Password", DisplayName: "Password", Rule: "All"},
|
||||||
|
{Name: "Verification code", DisplayName: "Verification code", Rule: "All"},
|
||||||
|
{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"},
|
||||||
|
},
|
||||||
SignupItems: []*SignupItem{
|
SignupItems: []*SignupItem{
|
||||||
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
|
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
|
||||||
{Name: "Username", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
{Name: "Username", Visible: true, Required: true, Prompted: false, Rule: "None"},
|
||||||
@@ -192,6 +197,7 @@ func initBuiltInApplication() {
|
|||||||
},
|
},
|
||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
RedirectUris: []string{},
|
RedirectUris: []string{},
|
||||||
|
TokenFields: []string{},
|
||||||
ExpireInHours: 168,
|
ExpireInHours: 168,
|
||||||
FormOffset: 2,
|
FormOffset: 2,
|
||||||
}
|
}
|
||||||
|
@@ -136,17 +136,23 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
|
|||||||
if application.Providers == nil {
|
if application.Providers == nil {
|
||||||
application.Providers = []*ProviderItem{}
|
application.Providers = []*ProviderItem{}
|
||||||
}
|
}
|
||||||
|
if application.SigninMethods == nil {
|
||||||
|
application.SigninMethods = []*SigninMethod{}
|
||||||
|
}
|
||||||
if application.SignupItems == nil {
|
if application.SignupItems == nil {
|
||||||
application.SignupItems = []*SignupItem{}
|
application.SignupItems = []*SignupItem{}
|
||||||
}
|
}
|
||||||
if application.GrantTypes == nil {
|
if application.GrantTypes == nil {
|
||||||
application.GrantTypes = []string{}
|
application.GrantTypes = []string{}
|
||||||
}
|
}
|
||||||
|
if application.Tags == nil {
|
||||||
|
application.Tags = []string{}
|
||||||
|
}
|
||||||
if application.RedirectUris == nil {
|
if application.RedirectUris == nil {
|
||||||
application.RedirectUris = []string{}
|
application.RedirectUris = []string{}
|
||||||
}
|
}
|
||||||
if application.Tags == nil {
|
if application.TokenFields == nil {
|
||||||
application.Tags = []string{}
|
application.TokenFields = []string{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, permission := range data.Permissions {
|
for _, permission := range data.Permissions {
|
||||||
|
134
object/invitation.go
Normal file
134
object/invitation.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/xorm-io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Invitation struct {
|
||||||
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
|
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
|
||||||
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
|
||||||
|
Code string `xorm:"varchar(100)" json:"code"`
|
||||||
|
Quota int `json:"quota"`
|
||||||
|
UsedCount int `json:"usedCount"`
|
||||||
|
|
||||||
|
Application string `xorm:"varchar(100)" json:"application"`
|
||||||
|
Username string `xorm:"varchar(100)" json:"username"`
|
||||||
|
Email string `xorm:"varchar(100)" json:"email"`
|
||||||
|
Phone string `xorm:"varchar(100)" json:"phone"`
|
||||||
|
|
||||||
|
SignupGroup string `xorm:"varchar(100)" json:"signupGroup"`
|
||||||
|
|
||||||
|
State string `xorm:"varchar(100)" json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInvitationCount(owner, field, value string) (int64, error) {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
return session.Count(&Invitation{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInvitations(owner string) ([]*Invitation, error) {
|
||||||
|
invitations := []*Invitation{}
|
||||||
|
err := ormer.Engine.Desc("created_time").Find(&invitations, &Invitation{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
return invitations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return invitations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationInvitations(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Invitation, error) {
|
||||||
|
invitations := []*Invitation{}
|
||||||
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Find(&invitations)
|
||||||
|
if err != nil {
|
||||||
|
return invitations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return invitations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInvitation(owner string, name string) (*Invitation, error) {
|
||||||
|
if owner == "" || name == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
invitation := Invitation{Owner: owner, Name: name}
|
||||||
|
existed, err := ormer.Engine.Get(&invitation)
|
||||||
|
if err != nil {
|
||||||
|
return &invitation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
return &invitation, nil
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInvitation(id string) (*Invitation, error) {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getInvitation(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateInvitation(id string, invitation *Invitation) (bool, error) {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if p, err := getInvitation(owner, name); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if p == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(invitation)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddInvitation(invitation *Invitation) (bool, error) {
|
||||||
|
affected, err := ormer.Engine.Insert(invitation)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteInvitation(invitation *Invitation) (bool, error) {
|
||||||
|
affected, err := ormer.Engine.ID(core.PK{invitation.Owner, invitation.Name}).Delete(&Invitation{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (invitation *Invitation) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", invitation.Owner, invitation.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyInvitation(id string) (payment *Payment, attachInfo map[string]interface{}, err error) {
|
||||||
|
return nil, nil, fmt.Errorf("the invitation: %s does not exist", id)
|
||||||
|
}
|
@@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
"github.com/thanhpk/randstr"
|
"github.com/thanhpk/randstr"
|
||||||
@@ -356,7 +357,8 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
|
|||||||
func GetExistUuids(owner string, uuids []string) ([]string, error) {
|
func GetExistUuids(owner string, uuids []string) ([]string, error) {
|
||||||
var existUuids []string
|
var existUuids []string
|
||||||
|
|
||||||
err := ormer.Engine.Table("user").Where("owner = ?", owner).Cols("ldap").
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
|
err := ormer.Engine.Table(tableNamePrefix+"user").Where("owner = ?", owner).Cols("ldap").
|
||||||
In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids)
|
In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return existUuids, err
|
return existUuids, err
|
||||||
|
129
object/ormer.go
129
object/ormer.go
@@ -36,16 +36,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ormer *Ormer = nil
|
ormer *Ormer = nil
|
||||||
isCreateDatabaseDefined = false
|
createDatabase = true
|
||||||
createDatabase = true
|
configPath = "conf/app.conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitFlag() {
|
func InitFlag() {
|
||||||
if !isCreateDatabaseDefined {
|
createDatabase = getCreateDatabaseFlag()
|
||||||
isCreateDatabaseDefined = true
|
configPath = getConfigFlag()
|
||||||
createDatabase = getCreateDatabaseFlag()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCreateDatabaseFlag() bool {
|
func getCreateDatabaseFlag() bool {
|
||||||
@@ -54,6 +52,12 @@ func getCreateDatabaseFlag() bool {
|
|||||||
return *res
|
return *res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getConfigFlag() string {
|
||||||
|
res := flag.String("config", "conf/app.conf", "set it to \"/your/path/app.conf\" if your config file is not in: \"/conf/app.conf\"")
|
||||||
|
flag.Parse()
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
func InitConfig() {
|
func InitConfig() {
|
||||||
err := beego.LoadAppConfig("ini", "../conf/app.conf")
|
err := beego.LoadAppConfig("ini", "../conf/app.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -68,7 +72,7 @@ func InitConfig() {
|
|||||||
|
|
||||||
func InitAdapter() {
|
func InitAdapter() {
|
||||||
if conf.GetConfigString("driverName") == "" {
|
if conf.GetConfigString("driverName") == "" {
|
||||||
if !util.FileExist("conf/app.conf") {
|
if !util.FileExist(configPath) {
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -234,12 +238,37 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Group))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(User))
|
err = a.Engine.Sync2(new(User))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Group))
|
err = a.Engine.Sync2(new(Invitation))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Application))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Provider))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Resource))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Cert))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -269,17 +298,7 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Provider))
|
err = a.Engine.Sync2(new(Session))
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Application))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Resource))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -289,26 +308,6 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(VerificationRecord))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Webhook))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Syncer))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Cert))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Product))
|
err = a.Engine.Sync2(new(Product))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -319,6 +318,36 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Plan))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Pricing))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Subscription))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Syncer))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Webhook))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(VerificationRecord))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Ldap))
|
err = a.Engine.Sync2(new(Ldap))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -333,24 +362,4 @@ func (a *Ormer) createTable() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Session))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Subscription))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Plan))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Pricing))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -284,27 +284,31 @@ func removeGroupingPolicies(permission *Permission) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CasbinRequest = []interface{}
|
func Enforce(permission *Permission, request []string, permissionIds ...string) (bool, error) {
|
||||||
|
|
||||||
func Enforce(permission *Permission, request *CasbinRequest, permissionIds ...string) (bool, error) {
|
|
||||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return enforcer.Enforce(*request...)
|
// type transformation
|
||||||
|
interfaceRequest := util.StringToInterfaceArray(request)
|
||||||
|
|
||||||
|
return enforcer.Enforce(interfaceRequest...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BatchEnforce(permission *Permission, requests *[]CasbinRequest, permissionIds ...string) ([]bool, error) {
|
func BatchEnforce(permission *Permission, requests [][]string, permissionIds ...string) ([]bool, error) {
|
||||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return enforcer.BatchEnforce(*requests)
|
// type transformation
|
||||||
|
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||||
|
|
||||||
|
return enforcer.BatchEnforce(interfaceRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([]string, error) {
|
func getEnforcers(userId string) ([]*casbin.Enforcer, error) {
|
||||||
permissions, _, err := getPermissionsAndRolesByUser(userId)
|
permissions, _, err := getPermissionsAndRolesByUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -316,7 +320,8 @@ func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range allRoles {
|
for _, role := range allRoles {
|
||||||
permissionsByRole, err := GetPermissionsByRole(role)
|
var permissionsByRole []*Permission
|
||||||
|
permissionsByRole, err = GetPermissionsByRole(role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -324,29 +329,45 @@ func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([
|
|||||||
permissions = append(permissions, permissionsByRole...)
|
permissions = append(permissions, permissionsByRole...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var values []string
|
var enforcers []*casbin.Enforcer
|
||||||
for _, permission := range permissions {
|
for _, permission := range permissions {
|
||||||
enforcer, err := getPermissionEnforcer(permission)
|
var enforcer *casbin.Enforcer
|
||||||
|
enforcer, err = getPermissionEnforcer(permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
values = append(values, fn(enforcer)...)
|
enforcers = append(enforcers, enforcer)
|
||||||
}
|
}
|
||||||
|
return enforcers, nil
|
||||||
return values, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllObjects(userId string) ([]string, error) {
|
func GetAllObjects(userId string) ([]string, error) {
|
||||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
enforcers, err := getEnforcers(userId)
|
||||||
return enforcer.GetAllObjects()
|
if err != nil {
|
||||||
})
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := []string{}
|
||||||
|
for _, enforcer := range enforcers {
|
||||||
|
items := enforcer.GetAllObjects()
|
||||||
|
res = append(res, items...)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllActions(userId string) ([]string, error) {
|
func GetAllActions(userId string) ([]string, error) {
|
||||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
enforcers, err := getEnforcers(userId)
|
||||||
return enforcer.GetAllActions()
|
if err != nil {
|
||||||
})
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := []string{}
|
||||||
|
for _, enforcer := range enforcers {
|
||||||
|
items := enforcer.GetAllObjects()
|
||||||
|
res = append(res, items...)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllRoles(userId string) ([]string, error) {
|
func GetAllRoles(userId string) ([]string, error) {
|
||||||
|
@@ -52,7 +52,7 @@ type Provider struct {
|
|||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
DisableSsl bool `json:"disableSsl"` // If the provider type is WeChat, DisableSsl means EnableQRCode
|
DisableSsl bool `json:"disableSsl"` // If the provider type is WeChat, DisableSsl means EnableQRCode
|
||||||
Title string `xorm:"varchar(100)" json:"title"`
|
Title string `xorm:"varchar(100)" json:"title"`
|
||||||
Content string `xorm:"varchar(1000)" json:"content"` // If provider type is WeChat, Content means QRCode string by Base64 encoding
|
Content string `xorm:"varchar(2000)" json:"content"` // If provider type is WeChat, Content means QRCode string by Base64 encoding
|
||||||
Receiver string `xorm:"varchar(100)" json:"receiver"`
|
Receiver string `xorm:"varchar(100)" json:"receiver"`
|
||||||
|
|
||||||
RegionId string `xorm:"varchar(100)" json:"regionId"`
|
RegionId string `xorm:"varchar(100)" json:"regionId"`
|
||||||
|
@@ -266,10 +266,9 @@ func (role *Role) GetId() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRolesByUserInternal(userId string) ([]*Role, error) {
|
func getRolesByUserInternal(userId string) ([]*Role, error) {
|
||||||
roles := []*Role{}
|
|
||||||
user, err := GetUser(userId)
|
user, err := GetUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return roles, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, fmt.Errorf("The user: %s doesn't exist", userId)
|
return nil, fmt.Errorf("The user: %s doesn't exist", userId)
|
||||||
@@ -280,9 +279,10 @@ func getRolesByUserInternal(userId string) ([]*Role, error) {
|
|||||||
query = query.Or("r.groups like ?", fmt.Sprintf("%%%s%%", group))
|
query = query.Or("r.groups like ?", fmt.Sprintf("%%%s%%", group))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roles := []*Role{}
|
||||||
err = query.Find(&roles)
|
err = query.Find(&roles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return roles, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := []*Role{}
|
res := []*Role{}
|
||||||
@@ -291,14 +291,13 @@ func getRolesByUserInternal(userId string) ([]*Role, error) {
|
|||||||
res = append(res, role)
|
res = append(res, role)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRolesByUser(userId string) ([]*Role, error) {
|
func getRolesByUser(userId string) ([]*Role, error) {
|
||||||
roles, err := getRolesByUserInternal(userId)
|
roles, err := getRolesByUserInternal(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return roles, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
allRolesIds := []string{}
|
allRolesIds := []string{}
|
||||||
@@ -379,15 +378,11 @@ func GetMaskedRoles(roles []*Role) []*Role {
|
|||||||
|
|
||||||
// GetAncestorRoles returns a list of roles that contain the given roleIds
|
// GetAncestorRoles returns a list of roles that contain the given roleIds
|
||||||
func GetAncestorRoles(roleIds ...string) ([]*Role, error) {
|
func GetAncestorRoles(roleIds ...string) ([]*Role, error) {
|
||||||
var (
|
|
||||||
result = []*Role{}
|
|
||||||
roleMap = make(map[string]*Role)
|
|
||||||
visited = make(map[string]bool)
|
|
||||||
)
|
|
||||||
if len(roleIds) == 0 {
|
if len(roleIds) == 0 {
|
||||||
return result, nil
|
return []*Role{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visited := map[string]bool{}
|
||||||
for _, roleId := range roleIds {
|
for _, roleId := range roleIds {
|
||||||
visited[roleId] = true
|
visited[roleId] = true
|
||||||
}
|
}
|
||||||
@@ -399,25 +394,26 @@ func GetAncestorRoles(roleIds ...string) ([]*Role, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roleMap := map[string]*Role{}
|
||||||
for _, r := range allRoles {
|
for _, r := range allRoles {
|
||||||
roleMap[r.GetId()] = r
|
roleMap[r.GetId()] = r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second, find all the roles that contain father roles
|
// find all the roles that contain father roles
|
||||||
|
res := []*Role{}
|
||||||
for _, r := range allRoles {
|
for _, r := range allRoles {
|
||||||
isContain, ok := visited[r.GetId()]
|
isContain, ok := visited[r.GetId()]
|
||||||
if isContain {
|
if isContain {
|
||||||
result = append(result, r)
|
res = append(res, r)
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
rId := r.GetId()
|
rId := r.GetId()
|
||||||
visited[rId] = containsRole(r, roleMap, visited, roleIds...)
|
visited[rId] = containsRole(r, roleMap, visited, roleIds...)
|
||||||
if visited[rId] {
|
if visited[rId] {
|
||||||
result = append(result, r)
|
res = append(res, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return res, nil
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// containsRole is a helper function to check if a roles is related to any role in the given list roles
|
// containsRole is a helper function to check if a roles is related to any role in the given list roles
|
||||||
|
@@ -72,6 +72,10 @@ func GetTruncatedPath(provider *Provider, fullFilePath string, limit int) string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
|
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
|
||||||
|
if provider.Domain != "" && !strings.HasPrefix(provider.Domain, "http://") && !strings.HasPrefix(provider.Domain, "https://") {
|
||||||
|
provider.Domain = fmt.Sprintf("https://%s", provider.Domain)
|
||||||
|
}
|
||||||
|
|
||||||
escapedPath := util.UrlJoin(provider.PathPrefix, fullFilePath)
|
escapedPath := util.UrlJoin(provider.PathPrefix, fullFilePath)
|
||||||
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
|
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
|
||||||
|
|
||||||
@@ -79,9 +83,6 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
|
|||||||
if provider.Type != "Local File System" {
|
if provider.Type != "Local File System" {
|
||||||
// provider.Domain = "https://cdn.casbin.com/casdoor/"
|
// provider.Domain = "https://cdn.casbin.com/casdoor/"
|
||||||
host = util.GetUrlHost(provider.Domain)
|
host = util.GetUrlHost(provider.Domain)
|
||||||
if !strings.HasPrefix(host, "http://") && !strings.HasPrefix(host, "https://") {
|
|
||||||
host = fmt.Sprintf("https://%s", host)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// provider.Domain = "http://localhost:8000" or "https://door.casdoor.com"
|
// provider.Domain = "http://localhost:8000" or "https://door.casdoor.com"
|
||||||
host = util.UrlJoin(provider.Domain, "/files")
|
host = util.UrlJoin(provider.Domain, "/files")
|
||||||
@@ -90,9 +91,12 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
|
|||||||
host = util.UrlJoin(host, provider.Bucket)
|
host = util.UrlJoin(host, provider.Bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileUrl := util.UrlJoin(host, escapePath(objectKey))
|
fileUrl := ""
|
||||||
|
if host != "" {
|
||||||
|
fileUrl = util.UrlJoin(host, escapePath(objectKey))
|
||||||
|
}
|
||||||
|
|
||||||
if hasTimestamp {
|
if fileUrl != "" && hasTimestamp {
|
||||||
fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
|
fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -116,22 +116,35 @@ func GetSyncer(id string) (*Syncer, error) {
|
|||||||
return getSyncer(owner, name)
|
return getSyncer(owner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMaskedSyncer(syncer *Syncer) *Syncer {
|
func GetMaskedSyncer(syncer *Syncer, errs ...error) (*Syncer, error) {
|
||||||
|
if len(errs) > 0 && errs[0] != nil {
|
||||||
|
return nil, errs[0]
|
||||||
|
}
|
||||||
|
|
||||||
if syncer == nil {
|
if syncer == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncer.Password != "" {
|
if syncer.Password != "" {
|
||||||
syncer.Password = "***"
|
syncer.Password = "***"
|
||||||
}
|
}
|
||||||
return syncer
|
return syncer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMaskedSyncers(syncers []*Syncer) []*Syncer {
|
func GetMaskedSyncers(syncers []*Syncer, errs ...error) ([]*Syncer, error) {
|
||||||
for _, syncer := range syncers {
|
if len(errs) > 0 && errs[0] != nil {
|
||||||
syncer = GetMaskedSyncer(syncer)
|
return nil, errs[0]
|
||||||
}
|
}
|
||||||
return syncers
|
|
||||||
|
var err error
|
||||||
|
for _, syncer := range syncers {
|
||||||
|
syncer, err = GetMaskedSyncer(syncer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return syncers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateSyncer(id string, syncer *Syncer) (bool, error) {
|
func UpdateSyncer(id string, syncer *Syncer) (bool, error) {
|
||||||
|
@@ -54,6 +54,15 @@ func (syncer *Syncer) syncUsers() error {
|
|||||||
var affiliationMap map[int]string
|
var affiliationMap map[int]string
|
||||||
if syncer.AffiliationTable != "" {
|
if syncer.AffiliationTable != "" {
|
||||||
_, affiliationMap, err = syncer.getAffiliationMap()
|
_, affiliationMap, err = syncer.getAffiliationMap()
|
||||||
|
if err != nil {
|
||||||
|
line := fmt.Sprintf("[%s] %s\n", util.GetCurrentTime(), err.Error())
|
||||||
|
_, err2 := updateSyncerErrorText(syncer, line)
|
||||||
|
if err2 != nil {
|
||||||
|
panic(err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key := syncer.getKey()
|
key := syncer.getKey()
|
||||||
|
@@ -16,6 +16,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@@ -270,6 +271,34 @@ func getClaimsWithoutThirdIdp(claims Claims) ClaimsWithoutThirdIdp {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getClaimsCustom(claims Claims, tokenField []string) jwt.MapClaims {
|
||||||
|
res := make(jwt.MapClaims)
|
||||||
|
|
||||||
|
userValue := reflect.ValueOf(claims.User).Elem()
|
||||||
|
|
||||||
|
res["iss"] = claims.RegisteredClaims.Issuer
|
||||||
|
res["sub"] = claims.RegisteredClaims.Subject
|
||||||
|
res["aud"] = claims.RegisteredClaims.Audience
|
||||||
|
res["exp"] = claims.RegisteredClaims.ExpiresAt
|
||||||
|
res["nbf"] = claims.RegisteredClaims.NotBefore
|
||||||
|
res["iat"] = claims.RegisteredClaims.IssuedAt
|
||||||
|
res["jti"] = claims.RegisteredClaims.ID
|
||||||
|
res["tokenType"] = claims.TokenType
|
||||||
|
res["nonce"] = claims.Nonce
|
||||||
|
res["tag"] = claims.Tag
|
||||||
|
res["scope"] = claims.Scope
|
||||||
|
|
||||||
|
for _, field := range tokenField {
|
||||||
|
userField := userValue.FieldByName(field)
|
||||||
|
if userField.IsValid() {
|
||||||
|
newfield := util.SnakeToCamel(util.CamelToSnakeCase(field))
|
||||||
|
res[newfield] = userField.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func refineUser(user *User) *User {
|
func refineUser(user *User) *User {
|
||||||
user.Password = ""
|
user.Password = ""
|
||||||
|
|
||||||
@@ -329,20 +358,30 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
|
|||||||
var refreshToken *jwt.Token
|
var refreshToken *jwt.Token
|
||||||
|
|
||||||
// the JWT token length in "JWT-Empty" mode will be very short, as User object only has two properties: owner and name
|
// the JWT token length in "JWT-Empty" mode will be very short, as User object only has two properties: owner and name
|
||||||
if application.TokenFormat == "JWT-Empty" {
|
if application.TokenFormat == "JWT" {
|
||||||
claimsShort := getShortClaims(claims)
|
|
||||||
|
|
||||||
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
|
||||||
claimsShort.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
|
||||||
claimsShort.TokenType = "refresh-token"
|
|
||||||
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
|
||||||
} else {
|
|
||||||
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
|
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
|
||||||
|
|
||||||
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
|
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
|
||||||
claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
||||||
claimsWithoutThirdIdp.TokenType = "refresh-token"
|
claimsWithoutThirdIdp.TokenType = "refresh-token"
|
||||||
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
|
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
|
||||||
|
} else if application.TokenFormat == "JWT-Empty" {
|
||||||
|
claimsShort := getShortClaims(claims)
|
||||||
|
|
||||||
|
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
||||||
|
claimsShort.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
||||||
|
claimsShort.TokenType = "refresh-token"
|
||||||
|
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
|
||||||
|
} else if application.TokenFormat == "JWT-Custom" {
|
||||||
|
claimsCustom := getClaimsCustom(claims, application.TokenFields)
|
||||||
|
|
||||||
|
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsCustom)
|
||||||
|
refreshClaims := getClaimsCustom(claims, application.TokenFields)
|
||||||
|
refreshClaims["exp"] = jwt.NewNumericDate(refreshExpireTime)
|
||||||
|
refreshClaims["TokenType"] = "refresh-token"
|
||||||
|
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, refreshClaims)
|
||||||
|
} else {
|
||||||
|
return "", "", "", fmt.Errorf("unknown application TokenFormat: %s", application.TokenFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := getCertByApplication(application)
|
cert, err := getCertByApplication(application)
|
||||||
|
@@ -867,7 +867,8 @@ func GetUserInfo(user *User, scope string, aud string, host string) *Userinfo {
|
|||||||
}
|
}
|
||||||
if strings.Contains(scope, "email") {
|
if strings.Contains(scope, "email") {
|
||||||
resp.Email = user.Email
|
resp.Email = user.Email
|
||||||
resp.EmailVerified = user.EmailVerified
|
// resp.EmailVerified = user.EmailVerified
|
||||||
|
resp.EmailVerified = true
|
||||||
}
|
}
|
||||||
if strings.Contains(scope, "address") {
|
if strings.Contains(scope, "address") {
|
||||||
resp.Address = user.Location
|
resp.Address = user.Location
|
||||||
@@ -886,6 +887,18 @@ func (user *User) GetId() string {
|
|||||||
return fmt.Sprintf("%s/%s", user.Owner, user.Name)
|
return fmt.Sprintf("%s/%s", user.Owner, user.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) GetFriendlyName() string {
|
||||||
|
if user.FirstName != "" && user.LastName != "" {
|
||||||
|
return fmt.Sprintf("%s, %s", user.FirstName, user.LastName)
|
||||||
|
} else if user.DisplayName != "" {
|
||||||
|
return user.DisplayName
|
||||||
|
} else if user.Name != "" {
|
||||||
|
return user.Name
|
||||||
|
} else {
|
||||||
|
return user.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func isUserIdGlobalAdmin(userId string) bool {
|
func isUserIdGlobalAdmin(userId string) bool {
|
||||||
return strings.HasPrefix(userId, "built-in/") || strings.HasPrefix(userId, "app/")
|
return strings.HasPrefix(userId, "built-in/") || strings.HasPrefix(userId, "app/")
|
||||||
}
|
}
|
||||||
|
@@ -89,7 +89,10 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||||
content := fmt.Sprintf(provider.Content, code)
|
content := strings.Replace(provider.Content, "%s", code, 1)
|
||||||
|
if user != nil {
|
||||||
|
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
if err := IsAllowSend(user, remoteAddr, provider.Category); err != nil {
|
if err := IsAllowSend(user, remoteAddr, provider.Category); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -24,16 +24,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
headerOrigin = "Origin"
|
headerOrigin = "Origin"
|
||||||
headerAllowOrigin = "Access-Control-Allow-Origin"
|
headerAllowOrigin = "Access-Control-Allow-Origin"
|
||||||
headerAllowMethods = "Access-Control-Allow-Methods"
|
headerAllowMethods = "Access-Control-Allow-Methods"
|
||||||
headerAllowHeaders = "Access-Control-Allow-Headers"
|
headerAllowHeaders = "Access-Control-Allow-Headers"
|
||||||
|
headerAllowCredentials = "Access-Control-Allow-Credentials"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setCorsHeaders(ctx *context.Context, origin string) {
|
func setCorsHeaders(ctx *context.Context, origin string) {
|
||||||
ctx.Output.Header(headerAllowOrigin, origin)
|
ctx.Output.Header(headerAllowOrigin, origin)
|
||||||
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS, DELETE")
|
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS, DELETE")
|
||||||
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
|
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
|
||||||
|
ctx.Output.Header(headerAllowCredentials, "true")
|
||||||
|
|
||||||
if ctx.Input.Method() == "OPTIONS" {
|
if ctx.Input.Method() == "OPTIONS" {
|
||||||
ctx.ResponseWriter.WriteHeader(http.StatusOK)
|
ctx.ResponseWriter.WriteHeader(http.StatusOK)
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package routers
|
// Package routers
|
||||||
// @APIVersion 1.376.1
|
// @APIVersion 1.503.0
|
||||||
// @Title Casdoor RESTful API
|
// @Title Casdoor RESTful API
|
||||||
// @Description Swagger Docs of Casdoor Backend API
|
// @Description Swagger Docs of Casdoor Backend API
|
||||||
// @Contact casbin@googlegroups.com
|
// @Contact casbin@googlegroups.com
|
||||||
@@ -73,6 +73,12 @@ func initAPI() {
|
|||||||
beego.Router("/api/get-default-application", &controllers.ApiController{}, "GET:GetDefaultApplication")
|
beego.Router("/api/get-default-application", &controllers.ApiController{}, "GET:GetDefaultApplication")
|
||||||
beego.Router("/api/get-organization-names", &controllers.ApiController{}, "GET:GetOrganizationNames")
|
beego.Router("/api/get-organization-names", &controllers.ApiController{}, "GET:GetOrganizationNames")
|
||||||
|
|
||||||
|
beego.Router("/api/get-groups", &controllers.ApiController{}, "GET:GetGroups")
|
||||||
|
beego.Router("/api/get-group", &controllers.ApiController{}, "GET:GetGroup")
|
||||||
|
beego.Router("/api/update-group", &controllers.ApiController{}, "POST:UpdateGroup")
|
||||||
|
beego.Router("/api/add-group", &controllers.ApiController{}, "POST:AddGroup")
|
||||||
|
beego.Router("/api/delete-group", &controllers.ApiController{}, "POST:DeleteGroup")
|
||||||
|
|
||||||
beego.Router("/api/get-global-users", &controllers.ApiController{}, "GET:GetGlobalUsers")
|
beego.Router("/api/get-global-users", &controllers.ApiController{}, "GET:GetGlobalUsers")
|
||||||
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
|
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
|
||||||
beego.Router("/api/get-sorted-users", &controllers.ApiController{}, "GET:GetSortedUsers")
|
beego.Router("/api/get-sorted-users", &controllers.ApiController{}, "GET:GetSortedUsers")
|
||||||
@@ -85,11 +91,41 @@ func initAPI() {
|
|||||||
beego.Router("/api/upload-users", &controllers.ApiController{}, "POST:UploadUsers")
|
beego.Router("/api/upload-users", &controllers.ApiController{}, "POST:UploadUsers")
|
||||||
beego.Router("/api/remove-user-from-group", &controllers.ApiController{}, "POST:RemoveUserFromGroup")
|
beego.Router("/api/remove-user-from-group", &controllers.ApiController{}, "POST:RemoveUserFromGroup")
|
||||||
|
|
||||||
beego.Router("/api/get-groups", &controllers.ApiController{}, "GET:GetGroups")
|
beego.Router("/api/get-invitations", &controllers.ApiController{}, "GET:GetInvitations")
|
||||||
beego.Router("/api/get-group", &controllers.ApiController{}, "GET:GetGroup")
|
beego.Router("/api/get-invitation", &controllers.ApiController{}, "GET:GetInvitation")
|
||||||
beego.Router("/api/update-group", &controllers.ApiController{}, "POST:UpdateGroup")
|
beego.Router("/api/update-invitation", &controllers.ApiController{}, "POST:UpdateInvitation")
|
||||||
beego.Router("/api/add-group", &controllers.ApiController{}, "POST:AddGroup")
|
beego.Router("/api/add-invitation", &controllers.ApiController{}, "POST:AddInvitation")
|
||||||
beego.Router("/api/delete-group", &controllers.ApiController{}, "POST:DeleteGroup")
|
beego.Router("/api/delete-invitation", &controllers.ApiController{}, "POST:DeleteInvitation")
|
||||||
|
beego.Router("/api/verify-invitation", &controllers.ApiController{}, "GET:VerifyInvitation")
|
||||||
|
|
||||||
|
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
||||||
|
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
||||||
|
beego.Router("/api/get-user-application", &controllers.ApiController{}, "GET:GetUserApplication")
|
||||||
|
beego.Router("/api/get-organization-applications", &controllers.ApiController{}, "GET:GetOrganizationApplications")
|
||||||
|
beego.Router("/api/update-application", &controllers.ApiController{}, "POST:UpdateApplication")
|
||||||
|
beego.Router("/api/add-application", &controllers.ApiController{}, "POST:AddApplication")
|
||||||
|
beego.Router("/api/delete-application", &controllers.ApiController{}, "POST:DeleteApplication")
|
||||||
|
|
||||||
|
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
|
||||||
|
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
|
||||||
|
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
|
||||||
|
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
|
||||||
|
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
|
||||||
|
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")
|
||||||
|
|
||||||
|
beego.Router("/api/get-resources", &controllers.ApiController{}, "GET:GetResources")
|
||||||
|
beego.Router("/api/get-resource", &controllers.ApiController{}, "GET:GetResource")
|
||||||
|
beego.Router("/api/update-resource", &controllers.ApiController{}, "POST:UpdateResource")
|
||||||
|
beego.Router("/api/add-resource", &controllers.ApiController{}, "POST:AddResource")
|
||||||
|
beego.Router("/api/delete-resource", &controllers.ApiController{}, "POST:DeleteResource")
|
||||||
|
beego.Router("/api/upload-resource", &controllers.ApiController{}, "POST:UploadResource")
|
||||||
|
|
||||||
|
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
|
||||||
|
beego.Router("/api/get-global-certs", &controllers.ApiController{}, "GET:GetGlobalCerts")
|
||||||
|
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
|
||||||
|
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
|
||||||
|
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
||||||
|
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
||||||
|
|
||||||
beego.Router("/api/get-roles", &controllers.ApiController{}, "GET:GetRoles")
|
beego.Router("/api/get-roles", &controllers.ApiController{}, "GET:GetRoles")
|
||||||
beego.Router("/api/get-role", &controllers.ApiController{}, "GET:GetRole")
|
beego.Router("/api/get-role", &controllers.ApiController{}, "GET:GetRole")
|
||||||
@@ -107,12 +143,6 @@ func initAPI() {
|
|||||||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
||||||
beego.Router("/api/upload-permissions", &controllers.ApiController{}, "POST:UploadPermissions")
|
beego.Router("/api/upload-permissions", &controllers.ApiController{}, "POST:UploadPermissions")
|
||||||
|
|
||||||
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
|
||||||
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
|
||||||
beego.Router("/api/get-all-objects", &controllers.ApiController{}, "GET:GetAllObjects")
|
|
||||||
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
|
||||||
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
|
||||||
|
|
||||||
beego.Router("/api/get-models", &controllers.ApiController{}, "GET:GetModels")
|
beego.Router("/api/get-models", &controllers.ApiController{}, "GET:GetModels")
|
||||||
beego.Router("/api/get-model", &controllers.ApiController{}, "GET:GetModel")
|
beego.Router("/api/get-model", &controllers.ApiController{}, "GET:GetModel")
|
||||||
beego.Router("/api/update-model", &controllers.ApiController{}, "POST:UpdateModel")
|
beego.Router("/api/update-model", &controllers.ApiController{}, "POST:UpdateModel")
|
||||||
@@ -135,53 +165,11 @@ func initAPI() {
|
|||||||
beego.Router("/api/add-enforcer", &controllers.ApiController{}, "POST:AddEnforcer")
|
beego.Router("/api/add-enforcer", &controllers.ApiController{}, "POST:AddEnforcer")
|
||||||
beego.Router("/api/delete-enforcer", &controllers.ApiController{}, "POST:DeleteEnforcer")
|
beego.Router("/api/delete-enforcer", &controllers.ApiController{}, "POST:DeleteEnforcer")
|
||||||
|
|
||||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
||||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
||||||
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
|
beego.Router("/api/get-all-objects", &controllers.ApiController{}, "GET:GetAllObjects")
|
||||||
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
|
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
||||||
beego.Router("/api/verify-code", &controllers.ApiController{}, "POST:VerifyCode")
|
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
||||||
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
|
|
||||||
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")
|
|
||||||
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
|
|
||||||
|
|
||||||
beego.Router("/api/get-ldap-users", &controllers.ApiController{}, "GET:GetLdapUsers")
|
|
||||||
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
|
|
||||||
beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
|
|
||||||
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
|
|
||||||
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
|
|
||||||
beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap")
|
|
||||||
beego.Router("/api/sync-ldap-users", &controllers.ApiController{}, "POST:SyncLdapUsers")
|
|
||||||
|
|
||||||
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
|
|
||||||
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
|
|
||||||
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
|
|
||||||
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
|
|
||||||
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
|
|
||||||
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")
|
|
||||||
|
|
||||||
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
|
||||||
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
|
||||||
beego.Router("/api/get-user-application", &controllers.ApiController{}, "GET:GetUserApplication")
|
|
||||||
beego.Router("/api/get-organization-applications", &controllers.ApiController{}, "GET:GetOrganizationApplications")
|
|
||||||
beego.Router("/api/update-application", &controllers.ApiController{}, "POST:UpdateApplication")
|
|
||||||
beego.Router("/api/add-application", &controllers.ApiController{}, "POST:AddApplication")
|
|
||||||
beego.Router("/api/delete-application", &controllers.ApiController{}, "POST:DeleteApplication")
|
|
||||||
|
|
||||||
beego.Router("/api/get-resources", &controllers.ApiController{}, "GET:GetResources")
|
|
||||||
beego.Router("/api/get-resource", &controllers.ApiController{}, "GET:GetResource")
|
|
||||||
beego.Router("/api/update-resource", &controllers.ApiController{}, "POST:UpdateResource")
|
|
||||||
beego.Router("/api/add-resource", &controllers.ApiController{}, "POST:AddResource")
|
|
||||||
beego.Router("/api/delete-resource", &controllers.ApiController{}, "POST:DeleteResource")
|
|
||||||
beego.Router("/api/upload-resource", &controllers.ApiController{}, "POST:UploadResource")
|
|
||||||
|
|
||||||
beego.Router("/api/get-tokens", &controllers.ApiController{}, "GET:GetTokens")
|
|
||||||
beego.Router("/api/get-token", &controllers.ApiController{}, "GET:GetToken")
|
|
||||||
beego.Router("/api/update-token", &controllers.ApiController{}, "POST:UpdateToken")
|
|
||||||
beego.Router("/api/add-token", &controllers.ApiController{}, "POST:AddToken")
|
|
||||||
beego.Router("/api/delete-token", &controllers.ApiController{}, "POST:DeleteToken")
|
|
||||||
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
|
||||||
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
|
||||||
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
|
|
||||||
|
|
||||||
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
|
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
|
||||||
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
|
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
|
||||||
@@ -190,43 +178,11 @@ func initAPI() {
|
|||||||
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
|
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
|
||||||
beego.Router("/api/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
|
beego.Router("/api/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
|
||||||
|
|
||||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
beego.Router("/api/get-tokens", &controllers.ApiController{}, "GET:GetTokens")
|
||||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
beego.Router("/api/get-token", &controllers.ApiController{}, "GET:GetToken")
|
||||||
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
beego.Router("/api/update-token", &controllers.ApiController{}, "POST:UpdateToken")
|
||||||
beego.Router("/api/add-webhook", &controllers.ApiController{}, "POST:AddWebhook")
|
beego.Router("/api/add-token", &controllers.ApiController{}, "POST:AddToken")
|
||||||
beego.Router("/api/delete-webhook", &controllers.ApiController{}, "POST:DeleteWebhook")
|
beego.Router("/api/delete-token", &controllers.ApiController{}, "POST:DeleteToken")
|
||||||
|
|
||||||
beego.Router("/api/get-syncers", &controllers.ApiController{}, "GET:GetSyncers")
|
|
||||||
beego.Router("/api/get-syncer", &controllers.ApiController{}, "GET:GetSyncer")
|
|
||||||
beego.Router("/api/update-syncer", &controllers.ApiController{}, "POST:UpdateSyncer")
|
|
||||||
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
|
||||||
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
|
||||||
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
|
||||||
|
|
||||||
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
|
|
||||||
beego.Router("/api/get-global-certs", &controllers.ApiController{}, "GET:GetGlobalCerts")
|
|
||||||
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
|
|
||||||
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
|
|
||||||
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
|
||||||
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
|
||||||
|
|
||||||
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
|
|
||||||
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
|
|
||||||
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
|
|
||||||
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
|
|
||||||
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
|
|
||||||
|
|
||||||
beego.Router("/api/get-plans", &controllers.ApiController{}, "GET:GetPlans")
|
|
||||||
beego.Router("/api/get-plan", &controllers.ApiController{}, "GET:GetPlan")
|
|
||||||
beego.Router("/api/update-plan", &controllers.ApiController{}, "POST:UpdatePlan")
|
|
||||||
beego.Router("/api/add-plan", &controllers.ApiController{}, "POST:AddPlan")
|
|
||||||
beego.Router("/api/delete-plan", &controllers.ApiController{}, "POST:DeletePlan")
|
|
||||||
|
|
||||||
beego.Router("/api/get-pricings", &controllers.ApiController{}, "GET:GetPricings")
|
|
||||||
beego.Router("/api/get-pricing", &controllers.ApiController{}, "GET:GetPricing")
|
|
||||||
beego.Router("/api/update-pricing", &controllers.ApiController{}, "POST:UpdatePricing")
|
|
||||||
beego.Router("/api/add-pricing", &controllers.ApiController{}, "POST:AddPricing")
|
|
||||||
beego.Router("/api/delete-pricing", &controllers.ApiController{}, "POST:DeletePricing")
|
|
||||||
|
|
||||||
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
|
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
|
||||||
beego.Router("/api/get-product", &controllers.ApiController{}, "GET:GetProduct")
|
beego.Router("/api/get-product", &controllers.ApiController{}, "GET:GetProduct")
|
||||||
@@ -244,6 +200,64 @@ func initAPI() {
|
|||||||
beego.Router("/api/notify-payment/?:owner/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
|
beego.Router("/api/notify-payment/?:owner/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
|
||||||
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
|
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
|
||||||
|
|
||||||
|
beego.Router("/api/get-plans", &controllers.ApiController{}, "GET:GetPlans")
|
||||||
|
beego.Router("/api/get-plan", &controllers.ApiController{}, "GET:GetPlan")
|
||||||
|
beego.Router("/api/update-plan", &controllers.ApiController{}, "POST:UpdatePlan")
|
||||||
|
beego.Router("/api/add-plan", &controllers.ApiController{}, "POST:AddPlan")
|
||||||
|
beego.Router("/api/delete-plan", &controllers.ApiController{}, "POST:DeletePlan")
|
||||||
|
|
||||||
|
beego.Router("/api/get-pricings", &controllers.ApiController{}, "GET:GetPricings")
|
||||||
|
beego.Router("/api/get-pricing", &controllers.ApiController{}, "GET:GetPricing")
|
||||||
|
beego.Router("/api/update-pricing", &controllers.ApiController{}, "POST:UpdatePricing")
|
||||||
|
beego.Router("/api/add-pricing", &controllers.ApiController{}, "POST:AddPricing")
|
||||||
|
beego.Router("/api/delete-pricing", &controllers.ApiController{}, "POST:DeletePricing")
|
||||||
|
|
||||||
|
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
|
||||||
|
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
|
||||||
|
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
|
||||||
|
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
|
||||||
|
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
|
||||||
|
|
||||||
|
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
||||||
|
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
|
||||||
|
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
|
||||||
|
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
|
||||||
|
beego.Handler("/api/metrics", promhttp.Handler())
|
||||||
|
|
||||||
|
beego.Router("/api/get-syncers", &controllers.ApiController{}, "GET:GetSyncers")
|
||||||
|
beego.Router("/api/get-syncer", &controllers.ApiController{}, "GET:GetSyncer")
|
||||||
|
beego.Router("/api/update-syncer", &controllers.ApiController{}, "POST:UpdateSyncer")
|
||||||
|
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
||||||
|
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
||||||
|
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
||||||
|
|
||||||
|
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||||
|
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||||
|
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
||||||
|
beego.Router("/api/add-webhook", &controllers.ApiController{}, "POST:AddWebhook")
|
||||||
|
beego.Router("/api/delete-webhook", &controllers.ApiController{}, "POST:DeleteWebhook")
|
||||||
|
|
||||||
|
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||||
|
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||||
|
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
|
||||||
|
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
|
||||||
|
beego.Router("/api/verify-code", &controllers.ApiController{}, "POST:VerifyCode")
|
||||||
|
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
|
||||||
|
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")
|
||||||
|
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
|
||||||
|
|
||||||
|
beego.Router("/api/get-ldap-users", &controllers.ApiController{}, "GET:GetLdapUsers")
|
||||||
|
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
|
||||||
|
beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
|
||||||
|
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
|
||||||
|
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
|
||||||
|
beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap")
|
||||||
|
beego.Router("/api/sync-ldap-users", &controllers.ApiController{}, "POST:SyncLdapUsers")
|
||||||
|
|
||||||
|
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
||||||
|
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
||||||
|
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
|
||||||
|
|
||||||
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
||||||
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
|
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
|
||||||
beego.Router("/api/send-notification", &controllers.ApiController{}, "POST:SendNotification")
|
beego.Router("/api/send-notification", &controllers.ApiController{}, "POST:SendNotification")
|
||||||
@@ -259,13 +273,6 @@ func initAPI() {
|
|||||||
beego.Router("/api/delete-mfa", &controllers.ApiController{}, "POST:DeleteMfa")
|
beego.Router("/api/delete-mfa", &controllers.ApiController{}, "POST:DeleteMfa")
|
||||||
beego.Router("/api/set-preferred-mfa", &controllers.ApiController{}, "POST:SetPreferredMfa")
|
beego.Router("/api/set-preferred-mfa", &controllers.ApiController{}, "POST:SetPreferredMfa")
|
||||||
|
|
||||||
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
|
||||||
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
|
|
||||||
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
|
|
||||||
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
|
|
||||||
|
|
||||||
beego.Handler("/api/metrics", promhttp.Handler())
|
|
||||||
|
|
||||||
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
|
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
|
||||||
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
|
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
|
||||||
|
|
||||||
|
@@ -34,6 +34,8 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
|
|||||||
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
case "Google Cloud Storage":
|
case "Google Cloud Storage":
|
||||||
return NewGoogleCloudStorageProvider(clientSecret, bucket, endpoint)
|
return NewGoogleCloudStorageProvider(clientSecret, bucket, endpoint)
|
||||||
|
case "Synology":
|
||||||
|
return NewSynologyNasStorageProvider(clientId, clientSecret, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
31
storage/synology_nas.go
Normal file
31
storage/synology_nas.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casdoor/oss"
|
||||||
|
"github.com/casdoor/oss/synology"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewSynologyNasStorageProvider(clientId string, clientSecret string, endpoint string) oss.StorageInterface {
|
||||||
|
sp := synology.New(&synology.Config{
|
||||||
|
AccessID: clientId,
|
||||||
|
AccessKey: clientSecret,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
SharedFolder: "/home",
|
||||||
|
})
|
||||||
|
|
||||||
|
return sp
|
||||||
|
}
|
1035
swagger/swagger.json
1035
swagger/swagger.json
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ swagger: "2.0"
|
|||||||
info:
|
info:
|
||||||
title: Casdoor RESTful API
|
title: Casdoor RESTful API
|
||||||
description: Swagger Docs of Casdoor Backend API
|
description: Swagger Docs of Casdoor Backend API
|
||||||
version: 1.376.1
|
version: 1.503.0
|
||||||
contact:
|
contact:
|
||||||
email: casbin@googlegroups.com
|
email: casbin@googlegroups.com
|
||||||
basePath: /
|
basePath: /
|
||||||
@@ -31,6 +31,17 @@ paths:
|
|||||||
description: ""
|
description: ""
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.OidcDiscovery'
|
$ref: '#/definitions/object.OidcDiscovery'
|
||||||
|
/api/Callback:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Callback API
|
||||||
|
description: Get Login Error Counts
|
||||||
|
operationId: ApiController.Callback
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Userinfo'
|
||||||
/api/add-adapter:
|
/api/add-adapter:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -121,6 +132,24 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/add-invitation:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: add invitation
|
||||||
|
operationId: ApiController.AddInvitation
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: The details of the invitation
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Invitation'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/add-ldap:
|
/api/add-ldap:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -442,162 +471,10 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/api/Callback:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Callback API
|
|
||||||
description: Get Login Error Counts
|
|
||||||
operationId: ApiController.Callback
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/api/get-captcha:
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- Login API
|
|
||||||
operationId: ApiController.GetCaptcha
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/api/get-captcha-status:
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- Token API
|
|
||||||
description: Get Login Error Counts
|
|
||||||
operationId: ApiController.GetCaptchaStatus
|
|
||||||
parameters:
|
|
||||||
- in: query
|
|
||||||
name: id
|
|
||||||
description: The id ( owner/name ) of user
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/controllers.Response'
|
|
||||||
/api/api/get-webhook-event:
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- GetWebhookEventType API
|
|
||||||
operationId: ApiController.GetWebhookEventType
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/api/reset-email-or-phone:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Account API
|
|
||||||
operationId: ApiController.ResetEmailOrPhone
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/api/send-email:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Service API
|
|
||||||
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
|
||||||
operationId: ApiController.SendEmail
|
|
||||||
parameters:
|
|
||||||
- in: query
|
|
||||||
name: clientId
|
|
||||||
description: The clientId of the application
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: clientSecret
|
|
||||||
description: The clientSecret of the application
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: body
|
|
||||||
name: from
|
|
||||||
description: Details of the email request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/controllers.EmailForm'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/Response'
|
|
||||||
/api/api/send-notification:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Service API
|
|
||||||
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
|
||||||
operationId: ApiController.SendNotification
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: from
|
|
||||||
description: Details of the notification request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/controllers.NotificationForm'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/Response'
|
|
||||||
/api/api/send-sms:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Service API
|
|
||||||
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
|
||||||
operationId: ApiController.SendSms
|
|
||||||
parameters:
|
|
||||||
- in: query
|
|
||||||
name: clientId
|
|
||||||
description: The clientId of the application
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: clientSecret
|
|
||||||
description: The clientSecret of the application
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: body
|
|
||||||
name: from
|
|
||||||
description: Details of the sms request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/controllers.SmsForm'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/Response'
|
|
||||||
/api/api/verify-code:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Verification API
|
|
||||||
operationId: ApiController.VerifyCode
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/api/webhook:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- HandleOfficialAccountEvent API
|
|
||||||
operationId: ApiController.HandleOfficialAccountEvent
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.Userinfo'
|
|
||||||
/api/batch-enforce:
|
/api/batch-enforce:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Enforce API
|
- Enforcer API
|
||||||
description: Call Casbin BatchEnforce API
|
description: Call Casbin BatchEnforce API
|
||||||
operationId: ApiController.BatchEnforce
|
operationId: ApiController.BatchEnforce
|
||||||
parameters:
|
parameters:
|
||||||
@@ -606,7 +483,9 @@ paths:
|
|||||||
description: array of casbin requests
|
description: array of casbin requests
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.CasbinRequest'
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: permissionId
|
name: permissionId
|
||||||
description: permission id
|
description: permission id
|
||||||
@@ -615,6 +494,10 @@ paths:
|
|||||||
name: modelId
|
name: modelId
|
||||||
description: model id
|
description: model id
|
||||||
type: string
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: owner
|
||||||
|
description: owner
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
@@ -718,7 +601,7 @@ paths:
|
|||||||
description: The enforcer object
|
description: The enforcer object
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.Enforce'
|
$ref: '#/definitions/object.Enforcer'
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: ""
|
description: ""
|
||||||
@@ -742,6 +625,24 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/delete-invitation:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: delete invitation
|
||||||
|
operationId: ApiController.DeleteInvitation
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: The details of the invitation
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Invitation'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/delete-ldap:
|
/api/delete-ldap:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -768,9 +669,9 @@ paths:
|
|||||||
operationId: ApiController.DeleteMfa
|
operationId: ApiController.DeleteMfa
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/delete-model:
|
/api/delete-model:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -1062,7 +963,7 @@ paths:
|
|||||||
/api/enforce:
|
/api/enforce:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Enforce API
|
- Enforcer API
|
||||||
description: Call Casbin Enforce API
|
description: Call Casbin Enforce API
|
||||||
operationId: ApiController.Enforce
|
operationId: ApiController.Enforce
|
||||||
parameters:
|
parameters:
|
||||||
@@ -1071,7 +972,9 @@ paths:
|
|||||||
description: Casbin request
|
description: Casbin request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.CasbinRequest'
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: permissionId
|
name: permissionId
|
||||||
description: permission id
|
description: permission id
|
||||||
@@ -1084,6 +987,10 @@ paths:
|
|||||||
name: resourceId
|
name: resourceId
|
||||||
description: resource id
|
description: resource id
|
||||||
type: string
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: owner
|
||||||
|
description: owner
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
@@ -1172,7 +1079,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/get-application:
|
/api/get-application:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1209,6 +1116,33 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/object.Application'
|
$ref: '#/definitions/object.Application'
|
||||||
|
/api/get-captcha:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Login API
|
||||||
|
operationId: ApiController.GetCaptcha
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Userinfo'
|
||||||
|
/api/get-captcha-status:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Token API
|
||||||
|
description: Get Login Error Counts
|
||||||
|
operationId: ApiController.GetCaptchaStatus
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: id
|
||||||
|
description: The id ( owner/name ) of user
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/get-cert:
|
/api/get-cert:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1248,7 +1182,7 @@ paths:
|
|||||||
/api/get-dashboard:
|
/api/get-dashboard:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- GetDashboard API
|
- System API
|
||||||
description: get information of dashboard
|
description: get information of dashboard
|
||||||
operationId: ApiController.GetDashboard
|
operationId: ApiController.GetDashboard
|
||||||
responses:
|
responses:
|
||||||
@@ -1272,7 +1206,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/get-email-and-phone:
|
/api/get-email-and-phone:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1406,6 +1340,42 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/object.Group'
|
$ref: '#/definitions/object.Group'
|
||||||
|
/api/get-invitation:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: get invitation
|
||||||
|
operationId: ApiController.GetInvitation
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: id
|
||||||
|
description: The id ( owner/name ) of the invitation
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Invitation'
|
||||||
|
/api/get-invitations:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: get invitations
|
||||||
|
operationId: ApiController.GetInvitations
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: owner
|
||||||
|
description: The owner of invitations
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/object.Invitation'
|
||||||
/api/get-ldap:
|
/api/get-ldap:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1433,7 +1403,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/LdapResp'
|
$ref: '#/definitions/controllers.LdapResp'
|
||||||
/api/get-ldaps:
|
/api/get-ldaps:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1781,7 +1751,7 @@ paths:
|
|||||||
/api/get-prometheus-info:
|
/api/get-prometheus-info:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Prometheus API
|
- System API
|
||||||
description: get Prometheus Info
|
description: get Prometheus Info
|
||||||
operationId: ApiController.GetPrometheusInfo
|
operationId: ApiController.GetPrometheusInfo
|
||||||
responses:
|
responses:
|
||||||
@@ -2265,6 +2235,16 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.Webhook'
|
$ref: '#/definitions/object.Webhook'
|
||||||
|
/api/get-webhook-event:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- System API
|
||||||
|
operationId: ApiController.GetWebhookEventType
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Userinfo'
|
||||||
/api/get-webhooks:
|
/api/get-webhooks:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -2392,8 +2372,50 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/login/oauth/access_token:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Token API
|
||||||
|
description: get OAuth access token
|
||||||
|
operationId: ApiController.GetOAuthToken
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: grant_type
|
||||||
|
description: OAuth grant type
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: client_id
|
||||||
|
description: OAuth client id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: client_secret
|
||||||
|
description: OAuth client secret
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: code
|
||||||
|
description: OAuth code
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.TokenWrapper'
|
||||||
|
"400":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.TokenError'
|
||||||
|
"401":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.TokenError'
|
||||||
/api/login/oauth/introspect:
|
/api/login/oauth/introspect:
|
||||||
post:
|
post:
|
||||||
|
tags:
|
||||||
|
- Login API
|
||||||
description: The introspection endpoint is an OAuth 2.0 endpoint that takes a
|
description: The introspection endpoint is an OAuth 2.0 endpoint that takes a
|
||||||
operationId: ApiController.IntrospectToken
|
operationId: ApiController.IntrospectToken
|
||||||
parameters:
|
parameters:
|
||||||
@@ -2496,9 +2518,9 @@ paths:
|
|||||||
operationId: ApiController.MfaSetupEnable
|
operationId: ApiController.MfaSetupEnable
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/mfa/setup/initiate:
|
/api/mfa/setup/initiate:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2518,9 +2540,9 @@ paths:
|
|||||||
operationId: ApiController.MfaSetupVerify
|
operationId: ApiController.MfaSetupVerify
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/notify-payment:
|
/api/notify-payment:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2539,6 +2561,16 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/reset-email-or-phone:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Account API
|
||||||
|
operationId: ApiController.ResetEmailOrPhone
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Userinfo'
|
||||||
/api/run-syncer:
|
/api/run-syncer:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -2557,6 +2589,80 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/send-email:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Service API
|
||||||
|
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
||||||
|
operationId: ApiController.SendEmail
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: clientId
|
||||||
|
description: The clientId of the application
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: clientSecret
|
||||||
|
description: The clientSecret of the application
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: body
|
||||||
|
name: from
|
||||||
|
description: Details of the email request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.EmailForm'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/send-notification:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Service API
|
||||||
|
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
||||||
|
operationId: ApiController.SendNotification
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: from
|
||||||
|
description: Details of the notification request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.NotificationForm'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/send-sms:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Service API
|
||||||
|
description: This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
||||||
|
operationId: ApiController.SendSms
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: clientId
|
||||||
|
description: The clientId of the application
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: clientSecret
|
||||||
|
description: The clientSecret of the application
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: body
|
||||||
|
name: from
|
||||||
|
description: Details of the sms request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.SmsForm'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/send-verification-code:
|
/api/send-verification-code:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2607,9 +2713,9 @@ paths:
|
|||||||
operationId: ApiController.SetPreferredMfa
|
operationId: ApiController.SetPreferredMfa
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/signup:
|
/api/signup:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2648,7 +2754,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/LdapSyncResp'
|
$ref: '#/definitions/controllers.LdapSyncResp'
|
||||||
/api/unlink:
|
/api/unlink:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -2774,6 +2880,29 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
|
/api/update-invitation:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: update invitation
|
||||||
|
operationId: ApiController.UpdateInvitation
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: id
|
||||||
|
description: The id ( owner/name ) of the invitation
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: The details of the invitation
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Invitation'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/update-ldap:
|
/api/update-ldap:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -3219,7 +3348,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/LaravelResponse'
|
$ref: '#/definitions/controllers.LaravelResponse'
|
||||||
/api/userinfo:
|
/api/userinfo:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3241,6 +3370,33 @@ paths:
|
|||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.Userinfo'
|
$ref: '#/definitions/object.Userinfo'
|
||||||
|
/api/verify-code:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Verification API
|
||||||
|
operationId: ApiController.VerifyCode
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/object.Userinfo'
|
||||||
|
/api/verify-invitation:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Invitation API
|
||||||
|
description: verify invitation
|
||||||
|
operationId: ApiController.VerifyInvitation
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: id
|
||||||
|
description: The id ( owner/name ) of the invitation
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The Response object
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controllers.Response'
|
||||||
/api/webauthn/signin/begin:
|
/api/webauthn/signin/begin:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3310,59 +3466,17 @@ paths:
|
|||||||
description: '"The Response object"'
|
description: '"The Response object"'
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/controllers.Response'
|
$ref: '#/definitions/controllers.Response'
|
||||||
/apiapi/login/oauth/access_token:
|
/api/webhook:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Token API
|
- System API
|
||||||
description: get OAuth access token
|
operationId: ApiController.HandleOfficialAccountEvent
|
||||||
operationId: ApiController.GetOAuthToken
|
|
||||||
parameters:
|
|
||||||
- in: query
|
|
||||||
name: grant_type
|
|
||||||
description: OAuth grant type
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: client_id
|
|
||||||
description: OAuth client id
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: client_secret
|
|
||||||
description: OAuth client secret
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: code
|
|
||||||
description: OAuth code
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The Response object
|
description: The Response object
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/object.TokenWrapper'
|
$ref: '#/definitions/object.Userinfo'
|
||||||
"400":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.TokenError'
|
|
||||||
"401":
|
|
||||||
description: The Response object
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/object.TokenError'
|
|
||||||
definitions:
|
definitions:
|
||||||
LaravelResponse:
|
|
||||||
title: LaravelResponse
|
|
||||||
type: object
|
|
||||||
LdapResp:
|
|
||||||
title: LdapResp
|
|
||||||
type: object
|
|
||||||
LdapSyncResp:
|
|
||||||
title: LdapSyncResp
|
|
||||||
type: object
|
|
||||||
Response:
|
|
||||||
title: Response
|
|
||||||
type: object
|
|
||||||
casbin.Enforcer:
|
casbin.Enforcer:
|
||||||
title: Enforcer
|
title: Enforcer
|
||||||
type: object
|
type: object
|
||||||
@@ -3385,6 +3499,46 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
|
controllers.LaravelResponse:
|
||||||
|
title: LaravelResponse
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
email_verified_at:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
updated_at:
|
||||||
|
type: string
|
||||||
|
controllers.LdapResp:
|
||||||
|
title: LdapResp
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
existUuids:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
users:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/object.LdapUser'
|
||||||
|
controllers.LdapSyncResp:
|
||||||
|
title: LdapSyncResp
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
exist:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/object.LdapUser'
|
||||||
|
failed:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/object.LdapUser'
|
||||||
controllers.NotificationForm:
|
controllers.NotificationForm:
|
||||||
title: NotificationForm
|
title: NotificationForm
|
||||||
type: object
|
type: object
|
||||||
@@ -3514,6 +3668,12 @@ definitions:
|
|||||||
expireInHours:
|
expireInHours:
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
failedSigninFrozenTime:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
failedSigninLimit:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
forgetUrl:
|
forgetUrl:
|
||||||
type: string
|
type: string
|
||||||
formBackgroundUrl:
|
formBackgroundUrl:
|
||||||
@@ -3568,6 +3728,10 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
signinHtml:
|
signinHtml:
|
||||||
type: string
|
type: string
|
||||||
|
signinMethods:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/object.SigninMethod'
|
||||||
signinUrl:
|
signinUrl:
|
||||||
type: string
|
type: string
|
||||||
signupHtml:
|
signupHtml:
|
||||||
@@ -3586,13 +3750,12 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
themeData:
|
themeData:
|
||||||
$ref: '#/definitions/object.ThemeData'
|
$ref: '#/definitions/object.ThemeData'
|
||||||
|
tokenFields:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
tokenFormat:
|
tokenFormat:
|
||||||
type: string
|
type: string
|
||||||
object.CasbinRequest:
|
|
||||||
title: CasbinRequest
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/object.CasbinRequest'
|
|
||||||
object.Cert:
|
object.Cert:
|
||||||
title: Cert
|
title: Cert
|
||||||
type: object
|
type: object
|
||||||
@@ -3621,9 +3784,6 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
object.Enforce:
|
|
||||||
title: Enforce
|
|
||||||
type: object
|
|
||||||
object.Enforcer:
|
object.Enforcer:
|
||||||
title: Enforcer
|
title: Enforcer
|
||||||
type: object
|
type: object
|
||||||
@@ -3750,6 +3910,40 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
|
object.Invitation:
|
||||||
|
title: Invitation
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
application:
|
||||||
|
type: string
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
createdTime:
|
||||||
|
type: string
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
owner:
|
||||||
|
type: string
|
||||||
|
phone:
|
||||||
|
type: string
|
||||||
|
quota:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
signupGroup:
|
||||||
|
type: string
|
||||||
|
state:
|
||||||
|
type: string
|
||||||
|
updatedTime:
|
||||||
|
type: string
|
||||||
|
usedCount:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
object.Ldap:
|
object.Ldap:
|
||||||
title: Ldap
|
title: Ldap
|
||||||
type: object
|
type: object
|
||||||
@@ -3786,6 +3980,46 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
|
object.LdapUser:
|
||||||
|
title: LdapUser
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
EmailAddress:
|
||||||
|
type: string
|
||||||
|
Mail:
|
||||||
|
type: string
|
||||||
|
MobileTelephoneNumber:
|
||||||
|
type: string
|
||||||
|
PostalAddress:
|
||||||
|
type: string
|
||||||
|
RegisteredAddress:
|
||||||
|
type: string
|
||||||
|
TelephoneNumber:
|
||||||
|
type: string
|
||||||
|
address:
|
||||||
|
type: string
|
||||||
|
cn:
|
||||||
|
type: string
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
gidNumber:
|
||||||
|
type: string
|
||||||
|
groupId:
|
||||||
|
type: string
|
||||||
|
memberOf:
|
||||||
|
type: string
|
||||||
|
mobile:
|
||||||
|
type: string
|
||||||
|
uid:
|
||||||
|
type: string
|
||||||
|
uidNumber:
|
||||||
|
type: string
|
||||||
|
userPrincipalName:
|
||||||
|
type: string
|
||||||
|
uuid:
|
||||||
|
type: string
|
||||||
object.ManagedAccount:
|
object.ManagedAccount:
|
||||||
title: ManagedAccount
|
title: ManagedAccount
|
||||||
type: object
|
type: object
|
||||||
@@ -4381,10 +4615,20 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
nameformat:
|
nameFormat:
|
||||||
type: string
|
type: string
|
||||||
value:
|
value:
|
||||||
type: string
|
type: string
|
||||||
|
object.SigninMethod:
|
||||||
|
title: SigninMethod
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
rule:
|
||||||
|
type: string
|
||||||
object.SignupItem:
|
object.SignupItem:
|
||||||
title: SignupItem
|
title: SignupItem
|
||||||
type: object
|
type: object
|
||||||
@@ -4397,6 +4641,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
prompted:
|
prompted:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
regex:
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
type: boolean
|
type: boolean
|
||||||
rule:
|
rule:
|
||||||
|
10
util/path.go
10
util/path.go
@@ -72,7 +72,15 @@ func GetUrlPath(urlString string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetUrlHost(urlString string) string {
|
func GetUrlHost(urlString string) string {
|
||||||
u, _ := url.Parse(urlString)
|
if urlString == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(urlString)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s://%s", u.Scheme, u.Host)
|
return fmt.Sprintf("%s://%s", u.Scheme, u.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -322,3 +322,23 @@ func GetUsernameFromEmail(email string) string {
|
|||||||
return tokens[0]
|
return tokens[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToInterfaceArray(array []string) []interface{} {
|
||||||
|
var interfaceArray []interface{}
|
||||||
|
for _, v := range array {
|
||||||
|
interfaceArray = append(interfaceArray, v)
|
||||||
|
}
|
||||||
|
return interfaceArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToInterfaceArray2d(arrays [][]string) [][]interface{} {
|
||||||
|
var interfaceArrays [][]interface{}
|
||||||
|
for _, req := range arrays {
|
||||||
|
var interfaceArray []interface{}
|
||||||
|
for _, r := range req {
|
||||||
|
interfaceArray = append(interfaceArray, r)
|
||||||
|
}
|
||||||
|
interfaceArrays = append(interfaceArrays, interfaceArray)
|
||||||
|
}
|
||||||
|
return interfaceArrays
|
||||||
|
}
|
||||||
|
126
web/src/App.js
126
web/src/App.js
@@ -15,62 +15,64 @@
|
|||||||
import React, {Component} from "react";
|
import React, {Component} from "react";
|
||||||
import "./App.less";
|
import "./App.less";
|
||||||
import {Helmet} from "react-helmet";
|
import {Helmet} from "react-helmet";
|
||||||
import Dashboard from "./basic/Dashboard";
|
|
||||||
import ShortcutsPage from "./basic/ShortcutsPage";
|
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
|
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
|
||||||
import {AppstoreTwoTone, BarsOutlined, DeploymentUnitOutlined, DollarTwoTone, DownOutlined, GithubOutlined, HomeTwoTone, InfoCircleFilled, LockTwoTone, LogoutOutlined, SafetyCertificateTwoTone, SettingOutlined, SettingTwoTone, ShareAltOutlined, WalletTwoTone} from "@ant-design/icons";
|
import {AppstoreTwoTone, BarsOutlined, DeploymentUnitOutlined, DollarTwoTone, DownOutlined, GithubOutlined, HomeTwoTone, InfoCircleFilled, LockTwoTone, LogoutOutlined, SafetyCertificateTwoTone, SettingOutlined, SettingTwoTone, ShareAltOutlined, WalletTwoTone} from "@ant-design/icons";
|
||||||
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result, Tooltip} from "antd";
|
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result, Tooltip} from "antd";
|
||||||
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
||||||
|
import AccountPage from "./account/AccountPage";
|
||||||
|
import Dashboard from "./basic/Dashboard";
|
||||||
|
import ShortcutsPage from "./basic/ShortcutsPage";
|
||||||
|
import AppListPage from "./basic/AppListPage";
|
||||||
import OrganizationListPage from "./OrganizationListPage";
|
import OrganizationListPage from "./OrganizationListPage";
|
||||||
import OrganizationEditPage from "./OrganizationEditPage";
|
import OrganizationEditPage from "./OrganizationEditPage";
|
||||||
|
import GroupEditPage from "./GroupEdit";
|
||||||
|
import GroupListPage from "./GroupList";
|
||||||
|
import GroupTreePage from "./GroupTreePage";
|
||||||
import UserListPage from "./UserListPage";
|
import UserListPage from "./UserListPage";
|
||||||
import UserEditPage from "./UserEditPage";
|
import UserEditPage from "./UserEditPage";
|
||||||
|
import InvitationListPage from "./InvitationListPage";
|
||||||
|
import InvitationEditPage from "./InvitationEditPage";
|
||||||
|
import ApplicationListPage from "./ApplicationListPage";
|
||||||
|
import ApplicationEditPage from "./ApplicationEditPage";
|
||||||
|
import ProviderListPage from "./ProviderListPage";
|
||||||
|
import ProviderEditPage from "./ProviderEditPage";
|
||||||
|
import ResourceListPage from "./ResourceListPage";
|
||||||
|
import CertListPage from "./CertListPage";
|
||||||
|
import CertEditPage from "./CertEditPage";
|
||||||
import RoleListPage from "./RoleListPage";
|
import RoleListPage from "./RoleListPage";
|
||||||
import RoleEditPage from "./RoleEditPage";
|
import RoleEditPage from "./RoleEditPage";
|
||||||
import PermissionListPage from "./PermissionListPage";
|
import PermissionListPage from "./PermissionListPage";
|
||||||
import PermissionEditPage from "./PermissionEditPage";
|
import PermissionEditPage from "./PermissionEditPage";
|
||||||
|
import ModelListPage from "./ModelListPage";
|
||||||
|
import ModelEditPage from "./ModelEditPage";
|
||||||
|
import AdapterListPage from "./AdapterListPage";
|
||||||
|
import AdapterEditPage from "./AdapterEditPage";
|
||||||
import EnforcerEditPage from "./EnforcerEditPage";
|
import EnforcerEditPage from "./EnforcerEditPage";
|
||||||
import EnforcerListPage from "./EnforcerListPage";
|
import EnforcerListPage from "./EnforcerListPage";
|
||||||
import GroupTreePage from "./GroupTreePage";
|
import SessionListPage from "./SessionListPage";
|
||||||
import GroupEditPage from "./GroupEdit";
|
|
||||||
import GroupListPage from "./GroupList";
|
|
||||||
import ProviderListPage from "./ProviderListPage";
|
|
||||||
import ProviderEditPage from "./ProviderEditPage";
|
|
||||||
import ApplicationListPage from "./ApplicationListPage";
|
|
||||||
import ApplicationEditPage from "./ApplicationEditPage";
|
|
||||||
import ResourceListPage from "./ResourceListPage";
|
|
||||||
import LdapEditPage from "./LdapEditPage";
|
|
||||||
import LdapSyncPage from "./LdapSyncPage";
|
|
||||||
import TokenListPage from "./TokenListPage";
|
import TokenListPage from "./TokenListPage";
|
||||||
import TokenEditPage from "./TokenEditPage";
|
import TokenEditPage from "./TokenEditPage";
|
||||||
import WebhookListPage from "./WebhookListPage";
|
|
||||||
import WebhookEditPage from "./WebhookEditPage";
|
|
||||||
import SyncerListPage from "./SyncerListPage";
|
|
||||||
import SyncerEditPage from "./SyncerEditPage";
|
|
||||||
import CertListPage from "./CertListPage";
|
|
||||||
import CertEditPage from "./CertEditPage";
|
|
||||||
import SubscriptionListPage from "./SubscriptionListPage";
|
|
||||||
import SubscriptionEditPage from "./SubscriptionEditPage";
|
|
||||||
import PricingListPage from "./PricingListPage";
|
|
||||||
import PricingEditPage from "./PricingEditPage";
|
|
||||||
import PlanListPage from "./PlanListPage";
|
|
||||||
import PlanEditPage from "./PlanEditPage";
|
|
||||||
import ProductListPage from "./ProductListPage";
|
import ProductListPage from "./ProductListPage";
|
||||||
import ProductEditPage from "./ProductEditPage";
|
import ProductEditPage from "./ProductEditPage";
|
||||||
import ProductBuyPage from "./ProductBuyPage";
|
import ProductBuyPage from "./ProductBuyPage";
|
||||||
import PaymentListPage from "./PaymentListPage";
|
import PaymentListPage from "./PaymentListPage";
|
||||||
import PaymentEditPage from "./PaymentEditPage";
|
import PaymentEditPage from "./PaymentEditPage";
|
||||||
import PaymentResultPage from "./PaymentResultPage";
|
import PaymentResultPage from "./PaymentResultPage";
|
||||||
import ModelListPage from "./ModelListPage";
|
import PricingListPage from "./PricingListPage";
|
||||||
import ModelEditPage from "./ModelEditPage";
|
import PricingEditPage from "./PricingEditPage";
|
||||||
import AdapterListPage from "./AdapterListPage";
|
import PlanListPage from "./PlanListPage";
|
||||||
import AdapterEditPage from "./AdapterEditPage";
|
import PlanEditPage from "./PlanEditPage";
|
||||||
import SessionListPage from "./SessionListPage";
|
import SubscriptionListPage from "./SubscriptionListPage";
|
||||||
import MfaSetupPage from "./auth/MfaSetupPage";
|
import SubscriptionEditPage from "./SubscriptionEditPage";
|
||||||
import SystemInfo from "./SystemInfo";
|
import SystemInfo from "./SystemInfo";
|
||||||
import AccountPage from "./account/AccountPage";
|
import SyncerListPage from "./SyncerListPage";
|
||||||
import AppListPage from "./basic/AppListPage";
|
import SyncerEditPage from "./SyncerEditPage";
|
||||||
|
import WebhookListPage from "./WebhookListPage";
|
||||||
|
import WebhookEditPage from "./WebhookEditPage";
|
||||||
|
import LdapEditPage from "./LdapEditPage";
|
||||||
|
import LdapSyncPage from "./LdapSyncPage";
|
||||||
|
import MfaSetupPage from "./auth/MfaSetupPage";
|
||||||
import CustomGithubCorner from "./common/CustomGithubCorner";
|
import CustomGithubCorner from "./common/CustomGithubCorner";
|
||||||
import * as Conf from "./Conf";
|
import * as Conf from "./Conf";
|
||||||
|
|
||||||
@@ -153,7 +155,7 @@ class App extends Component {
|
|||||||
});
|
});
|
||||||
if (uri === "/" || uri.includes("/shortcuts") || uri.includes("/apps")) {
|
if (uri === "/" || uri.includes("/shortcuts") || uri.includes("/apps")) {
|
||||||
this.setState({selectedMenuKey: "/home"});
|
this.setState({selectedMenuKey: "/home"});
|
||||||
} else if (uri.includes("/organizations") || uri.includes("/trees") || uri.includes("/users") || uri.includes("/groups")) {
|
} else if (uri.includes("/organizations") || uri.includes("/trees") || uri.includes("/groups") || uri.includes("/users") || uri.includes("/invitations")) {
|
||||||
this.setState({selectedMenuKey: "/orgs"});
|
this.setState({selectedMenuKey: "/orgs"});
|
||||||
} else if (uri.includes("/applications") || uri.includes("/providers") || uri.includes("/resources") || uri.includes("/certs")) {
|
} else if (uri.includes("/applications") || uri.includes("/providers") || uri.includes("/resources") || uri.includes("/certs")) {
|
||||||
this.setState({selectedMenuKey: "/identity"});
|
this.setState({selectedMenuKey: "/identity"});
|
||||||
@@ -366,7 +368,11 @@ class App extends Component {
|
|||||||
if (this.state.account === undefined) {
|
if (this.state.account === undefined) {
|
||||||
return null;
|
return null;
|
||||||
} else if (this.state.account === null) {
|
} else if (this.state.account === null) {
|
||||||
return null;
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<LanguageSelect />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@@ -390,7 +396,7 @@ class App extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<OpenTour />
|
<OpenTour />
|
||||||
{Setting.isAdminUser(this.state.account) && !Setting.isMobile() &&
|
{Setting.isAdminUser(this.state.account) && !Setting.isMobile() && (this.state.uri.indexOf("/trees") === -1) &&
|
||||||
<OrganizationSelect
|
<OrganizationSelect
|
||||||
initValue={Setting.getOrganization()}
|
initValue={Setting.getOrganization()}
|
||||||
withAll={true}
|
withAll={true}
|
||||||
@@ -434,6 +440,7 @@ class App extends Component {
|
|||||||
Setting.getItem(<Link to="/organizations">{i18next.t("general:Organizations")}</Link>, "/organizations"),
|
Setting.getItem(<Link to="/organizations">{i18next.t("general:Organizations")}</Link>, "/organizations"),
|
||||||
Setting.getItem(<Link to="/groups">{i18next.t("general:Groups")}</Link>, "/groups"),
|
Setting.getItem(<Link to="/groups">{i18next.t("general:Groups")}</Link>, "/groups"),
|
||||||
Setting.getItem(<Link to="/users">{i18next.t("general:Users")}</Link>, "/users"),
|
Setting.getItem(<Link to="/users">{i18next.t("general:Users")}</Link>, "/users"),
|
||||||
|
Setting.getItem(<Link to="/invitations">{i18next.t("general:Invitations")}</Link>, "/invitations"),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
res.push(Setting.getItem(<Link style={{color: "black"}} to="/applications">{i18next.t("general:Identity")}</Link>, "/identity", <LockTwoTone />, [
|
res.push(Setting.getItem(<Link style={{color: "black"}} to="/applications">{i18next.t("general:Identity")}</Link>, "/identity", <LockTwoTone />, [
|
||||||
@@ -514,48 +521,49 @@ class App extends Component {
|
|||||||
<Route exact path="/groups/:organizationName/:groupName" render={(props) => this.renderLoginIfNotLoggedIn(<GroupEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/groups/:organizationName/:groupName" render={(props) => this.renderLoginIfNotLoggedIn(<GroupEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />} />
|
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />} />
|
||||||
|
<Route exact path="/invitations" render={(props) => this.renderLoginIfNotLoggedIn(<InvitationListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/invitations/:organizationName/:invitationName" render={(props) => this.renderLoginIfNotLoggedIn(<InvitationEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/certs/:organizationName/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/models" render={(props) => this.renderLoginIfNotLoggedIn(<ModelListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/models" render={(props) => this.renderLoginIfNotLoggedIn(<ModelListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/models/:organizationName/:modelName" render={(props) => this.renderLoginIfNotLoggedIn(<ModelEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/models/:organizationName/:modelName" render={(props) => this.renderLoginIfNotLoggedIn(<ModelEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/enforcers" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/enforcers/:organizationName/:enforcerName" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/adapters" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/adapters" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/enforcers" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/enforcers/:organizationName/:enforcerName" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
|
||||||
{/* <Route exact path="/resources/:resourceName" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceEditPage account={this.state.account} {...props} />)}/>*/}
|
|
||||||
<Route exact path="/ldap/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/ldap/sync/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/sessions" render={(props) => this.renderLoginIfNotLoggedIn(<SessionListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/sessions" render={(props) => this.renderLoginIfNotLoggedIn(<SessionListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/tokens/:tokenName" render={(props) => this.renderLoginIfNotLoggedIn(<TokenEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/tokens/:tokenName" render={(props) => this.renderLoginIfNotLoggedIn(<TokenEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/certs/:organizationName/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/plans" render={(props) => this.renderLoginIfNotLoggedIn(<PlanListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/plans/:organizationName/:planName" render={(props) => this.renderLoginIfNotLoggedIn(<PlanEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/pricings" render={(props) => this.renderLoginIfNotLoggedIn(<PricingListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/pricings/:organizationName/:pricingName" render={(props) => this.renderLoginIfNotLoggedIn(<PricingEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/subscriptions" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionListPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/subscriptions/:organizationName/:subscriptionName" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionEditPage account={this.state.account} {...props} />)} />
|
|
||||||
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:organizationName/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments/:organizationName/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:organizationName/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments/:organizationName/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/plans" render={(props) => this.renderLoginIfNotLoggedIn(<PlanListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/plans/:organizationName/:planName" render={(props) => this.renderLoginIfNotLoggedIn(<PlanEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/pricings" render={(props) => this.renderLoginIfNotLoggedIn(<PricingListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/pricings/:organizationName/:pricingName" render={(props) => this.renderLoginIfNotLoggedIn(<PricingEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/subscriptions" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/subscriptions/:organizationName/:subscriptionName" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/ldap/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
||||||
|
<Route exact path="/ldap/sync/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
|
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
|
||||||
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
||||||
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
|
||||||
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
||||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Card, Col, ConfigProvider, Input, InputNumber, List, Popover, Radio, Result, Row, Select, Space, Switch, Upload} from "antd";
|
import {Button, Card, Col, ConfigProvider, Input, InputNumber, Popover, Radio, Result, Row, Select, Switch, Upload} from "antd";
|
||||||
import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
|
import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
|
||||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||||
import * as CertBackend from "./backend/CertBackend";
|
import * as CertBackend from "./backend/CertBackend";
|
||||||
@@ -27,6 +27,7 @@ import LoginPage from "./auth/LoginPage";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import UrlTable from "./table/UrlTable";
|
import UrlTable from "./table/UrlTable";
|
||||||
import ProviderTable from "./table/ProviderTable";
|
import ProviderTable from "./table/ProviderTable";
|
||||||
|
import SigninMethodTable from "./table/SigninMethodTable";
|
||||||
import SignupTable from "./table/SignupTable";
|
import SignupTable from "./table/SignupTable";
|
||||||
import SamlAttributeTable from "./table/SamlAttributeTable";
|
import SamlAttributeTable from "./table/SamlAttributeTable";
|
||||||
import PromptPage from "./auth/PromptPage";
|
import PromptPage from "./auth/PromptPage";
|
||||||
@@ -140,10 +141,6 @@ class ApplicationEditPage extends React.Component {
|
|||||||
application.tags = [];
|
application.tags = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application.invitationCodes === null) {
|
|
||||||
application.invitationCodes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
application: application,
|
application: application,
|
||||||
});
|
});
|
||||||
@@ -385,10 +382,22 @@ class ApplicationEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Select virtual={false} style={{width: "100%"}} value={this.state.application.tokenFormat} onChange={(value => {this.updateApplicationField("tokenFormat", value);})}
|
<Select virtual={false} style={{width: "100%"}} value={this.state.application.tokenFormat} onChange={(value => {this.updateApplicationField("tokenFormat", value);})}
|
||||||
options={["JWT", "JWT-Empty"].map((item) => Setting.getOption(item, item))}
|
options={["JWT", "JWT-Empty", "JWT-Custom"].map((item) => Setting.getOption(item, item))}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("application:Token fields"), i18next.t("application:Token fields - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} disabled={this.state.application.tokenFormat !== "JWT-Custom"} mode="tags" showSearch style={{width: "100%"}} value={this.state.application.tokenFields} onChange={(value => {this.updateApplicationField("tokenFields", value);})}>
|
||||||
|
{
|
||||||
|
Setting.getUserCommonFields().map((item, index) => <Option key={index} value={item}>{item}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("application:Token expire"), i18next.t("application:Token expire - Tooltip"))} :
|
{Setting.getLabel(i18next.t("application:Token expire"), i18next.t("application:Token expire - Tooltip"))} :
|
||||||
@@ -424,18 +433,8 @@ class ApplicationEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("application:Failed signin frozen time"), i18next.t("application:Failed signin frozen time - Tooltip"))} :
|
{Setting.getLabel(i18next.t("application:Failed signin frozen time"), i18next.t("application:Failed signin frozen time - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<InputNumber style={{width: "150px"}} value={this.state.application.failedSigninfrozenTime} min={1} step={1} precision={0} addonAfter="Minutes" onChange={value => {
|
<InputNumber style={{width: "150px"}} value={this.state.application.failedSigninFrozenTime} min={1} step={1} precision={0} addonAfter="Minutes" onChange={value => {
|
||||||
this.updateApplicationField("failedSigninfrozenTime", value);
|
this.updateApplicationField("failedSigninFrozenTime", value);
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: "20px"}} >
|
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("application:Enable password"), i18next.t("application:Enable password - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={1} >
|
|
||||||
<Switch checked={this.state.application.enablePassword} onChange={checked => {
|
|
||||||
this.updateApplicationField("enablePassword", checked);
|
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -469,26 +468,6 @@ class ApplicationEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("application:Enable code signin"), i18next.t("application:Enable code signin - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={1} >
|
|
||||||
<Switch checked={this.state.application.enableCodeSignin} onChange={checked => {
|
|
||||||
this.updateApplicationField("enableCodeSignin", checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: "20px"}} >
|
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("application:Enable WebAuthn signin"), i18next.t("application:Enable WebAuthn signin - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={1} >
|
|
||||||
<Switch checked={this.state.application.enableWebAuthn} onChange={checked => {
|
|
||||||
this.updateApplicationField("enableWebAuthn", checked);
|
|
||||||
}} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||||
{Setting.getLabel(i18next.t("application:Enable Email linking"), i18next.t("application:Enable Email linking - Tooltip"))} :
|
{Setting.getLabel(i18next.t("application:Enable Email linking"), i18next.t("application:Enable Email linking - Tooltip"))} :
|
||||||
@@ -499,6 +478,20 @@ class ApplicationEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("application:Signin methods"), i18next.t("application:Signin methods - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<SigninMethodTable
|
||||||
|
title={i18next.t("application:Signin methods")}
|
||||||
|
table={this.state.application.signinMethods}
|
||||||
|
onUpdateTable={(value) => {
|
||||||
|
this.updateApplicationField("signinMethods", value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("application:Org choice mode"), i18next.t("application:Org choice mode - Tooltip"))} :
|
{Setting.getLabel(i18next.t("application:Org choice mode"), i18next.t("application:Org choice mode - Tooltip"))} :
|
||||||
@@ -800,7 +793,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Radio.Group onChange={e => {this.updateApplicationField("formOffset", e.target.value);}} value={this.state.application.formOffset}>
|
<Radio.Group buttonStyle="solid" onChange={e => {this.updateApplicationField("formOffset", e.target.value);}} value={this.state.application.formOffset}>
|
||||||
<Radio.Button value={1}>{i18next.t("application:Left")}</Radio.Button>
|
<Radio.Button value={1}>{i18next.t("application:Left")}</Radio.Button>
|
||||||
<Radio.Button value={2}>{i18next.t("application:Center")}</Radio.Button>
|
<Radio.Button value={2}>{i18next.t("application:Center")}</Radio.Button>
|
||||||
<Radio.Button value={3}>{i18next.t("application:Right")}</Radio.Button>
|
<Radio.Button value={3}>{i18next.t("application:Right")}</Radio.Button>
|
||||||
@@ -840,7 +833,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={22} style={{marginTop: "5px"}}>
|
<Col span={22} style={{marginTop: "5px"}}>
|
||||||
<Row>
|
<Row>
|
||||||
<Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
|
<Radio.Group buttonStyle="solid" value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
|
||||||
const {_, ...theme} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
|
const {_, ...theme} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
|
||||||
this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value});
|
this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value});
|
||||||
}} >
|
}} >
|
||||||
@@ -876,52 +869,6 @@ class ApplicationEditPage extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
|
||||||
{Setting.getLabel(i18next.t("application:Invitation code"), i18next.t("application:Invitation code - Tooltip"))} :
|
|
||||||
</Col>
|
|
||||||
<Col span={22} >
|
|
||||||
<List
|
|
||||||
header={
|
|
||||||
<Button type="primary" onClick={() => {
|
|
||||||
this.updateApplicationField("invitationCodes", Setting.addRow(this.state.application.invitationCodes, Setting.getRandomName()));
|
|
||||||
}
|
|
||||||
}>
|
|
||||||
{i18next.t("general:Add")}
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
dataSource={this.state.application.invitationCodes.map(code => {
|
|
||||||
return {code: code};
|
|
||||||
})}
|
|
||||||
renderItem={(item, index) => (
|
|
||||||
<List.Item key={index}>
|
|
||||||
<Space>
|
|
||||||
<Input value={item.code} onChange={e => {
|
|
||||||
const invitationCodes = [...this.state.application.invitationCodes];
|
|
||||||
invitationCodes[index] = e.target.value;
|
|
||||||
this.updateApplicationField("invitationCodes", invitationCodes);
|
|
||||||
}} />
|
|
||||||
</Space>
|
|
||||||
<Space>
|
|
||||||
<Button icon={<CopyOutlined />} onClick={() => {
|
|
||||||
copy(item.code);
|
|
||||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
|
||||||
}
|
|
||||||
}>
|
|
||||||
{i18next.t("general:Copy")}
|
|
||||||
</Button>
|
|
||||||
<Button type="primary" danger onClick={() => {
|
|
||||||
this.updateApplicationField("invitationCodes", this.state.application.invitationCodes.filter(code => code !== item.code));
|
|
||||||
}
|
|
||||||
}>
|
|
||||||
{i18next.t("general:Delete")}
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -950,7 +897,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
|
|
||||||
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${redirectUri}&scope=read&state=casdoor`;
|
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${redirectUri}&scope=read&state=casdoor`;
|
||||||
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||||
if (!this.state.application.enablePassword) {
|
if (!Setting.isPasswordEnabled(this.state.application)) {
|
||||||
signUpUrl = signInUrl.replace("/login/oauth/authorize", "/signup/oauth/authorize");
|
signUpUrl = signInUrl.replace("/login/oauth/authorize", "/signup/oauth/authorize");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,7 +921,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
}}>
|
}}>
|
||||||
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", overflow: "auto"}}>
|
<div style={{position: "relative", width: previewWidth, border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", overflow: "auto"}}>
|
||||||
{
|
{
|
||||||
this.state.application.enablePassword ? (
|
Setting.isPasswordEnabled(this.state.application) ? (
|
||||||
<div className="loginBackground" style={{backgroundImage: `url(${this.state.application?.formBackgroundUrl})`, overflow: "auto"}}>
|
<div className="loginBackground" style={{backgroundImage: `url(${this.state.application?.formBackgroundUrl})`, overflow: "auto"}}>
|
||||||
<SignupPage application={this.state.application} preview = "auto" />
|
<SignupPage application={this.state.application} preview = "auto" />
|
||||||
</div>
|
</div>
|
||||||
@@ -1049,6 +996,7 @@ class ApplicationEditPage extends React.Component {
|
|||||||
submitApplicationEdit(exitAfterSave) {
|
submitApplicationEdit(exitAfterSave) {
|
||||||
const application = Setting.deepCopy(this.state.application);
|
const application = Setting.deepCopy(this.state.application);
|
||||||
application.providers = application.providers?.filter(provider => this.state.providers.map(provider => provider.name).includes(provider.name));
|
application.providers = application.providers?.filter(provider => this.state.providers.map(provider => provider.name).includes(provider.name));
|
||||||
|
application.signinMethods = application.signinMethods?.filter(signinMethod => ["Password", "Verification code", "WebAuthn", "LDAP"].includes(signinMethod.name));
|
||||||
|
|
||||||
ApplicationBackend.updateApplication("admin", this.state.applicationName, application)
|
ApplicationBackend.updateApplication("admin", this.state.applicationName, application)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@@ -46,6 +46,11 @@ class ApplicationListPage extends BaseListPage {
|
|||||||
providers: [
|
providers: [
|
||||||
{name: "provider_captcha_default", canSignUp: false, canSignIn: false, canUnlink: false, prompted: false, signupGroup: "", rule: ""},
|
{name: "provider_captcha_default", canSignUp: false, canSignIn: false, canUnlink: false, prompted: false, signupGroup: "", rule: ""},
|
||||||
],
|
],
|
||||||
|
SigninMethods: [
|
||||||
|
{name: "Password", displayName: "Password", rule: "All"},
|
||||||
|
{name: "Verification code", displayName: "Verification code", rule: "All"},
|
||||||
|
{name: "WebAuthn", displayName: "WebAuthn", rule: "None"},
|
||||||
|
],
|
||||||
signupItems: [
|
signupItems: [
|
||||||
{name: "ID", visible: false, required: true, rule: "Random"},
|
{name: "ID", visible: false, required: true, rule: "Random"},
|
||||||
{name: "Username", visible: true, required: true, rule: "None"},
|
{name: "Username", visible: true, required: true, rule: "None"},
|
||||||
@@ -59,6 +64,7 @@ class ApplicationListPage extends BaseListPage {
|
|||||||
cert: "cert-built-in",
|
cert: "cert-built-in",
|
||||||
redirectUris: ["http://localhost:9000/callback"],
|
redirectUris: ["http://localhost:9000/callback"],
|
||||||
tokenFormat: "JWT",
|
tokenFormat: "JWT",
|
||||||
|
tokenFields: [],
|
||||||
expireInHours: 24 * 7,
|
expireInHours: 24 * 7,
|
||||||
refreshExpireInHours: 24 * 7,
|
refreshExpireInHours: 24 * 7,
|
||||||
formOffset: 2,
|
formOffset: 2,
|
||||||
|
@@ -25,6 +25,7 @@ class BaseListPage extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
|
organizationName: this.props.match?.params.organizationName || Setting.getRequestOrganization(this.props.account),
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {
|
pagination: {
|
||||||
current: 1,
|
current: 1,
|
||||||
@@ -39,6 +40,10 @@ class BaseListPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleOrganizationChange = () => {
|
handleOrganizationChange = () => {
|
||||||
|
this.setState({
|
||||||
|
organizationName: this.props.match?.params.organizationName || Setting.getRequestOrganization(this.props.account),
|
||||||
|
});
|
||||||
|
|
||||||
const {pagination} = this.state;
|
const {pagination} = this.state;
|
||||||
this.fetch({pagination});
|
this.fetch({pagination});
|
||||||
};
|
};
|
||||||
|
282
web/src/InvitationEditPage.js
Normal file
282
web/src/InvitationEditPage.js
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {Button, Card, Col, Input, InputNumber, Row, Select} from "antd";
|
||||||
|
import * as InvitationBackend from "./backend/InvitationBackend";
|
||||||
|
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||||
|
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
|
class InvitationEditPage extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||||
|
invitationName: props.match.params.invitationName,
|
||||||
|
invitation: null,
|
||||||
|
organizations: [],
|
||||||
|
applications: [],
|
||||||
|
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
UNSAFE_componentWillMount() {
|
||||||
|
this.getInvitation();
|
||||||
|
this.getOrganizations();
|
||||||
|
this.getApplicationsByOrganization(this.state.organizationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
getInvitation() {
|
||||||
|
InvitationBackend.getInvitation(this.state.organizationName, this.state.invitationName)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data === null) {
|
||||||
|
this.props.history.push("/404");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
invitation: res.data,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrganizations() {
|
||||||
|
OrganizationBackend.getOrganizations("admin")
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
organizations: res.data || [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getApplicationsByOrganization(organizationName) {
|
||||||
|
ApplicationBackend.getApplicationsByOrganization("admin", organizationName)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
applications: res.data || [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parseInvitationField(key, value) {
|
||||||
|
if ([""].includes(key)) {
|
||||||
|
value = Setting.myParseInt(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInvitationField(key, value) {
|
||||||
|
value = this.parseInvitationField(key, value);
|
||||||
|
|
||||||
|
const invitation = this.state.invitation;
|
||||||
|
invitation[key] = value;
|
||||||
|
this.setState({
|
||||||
|
invitation: invitation,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderInvitation() {
|
||||||
|
const isCreatedByPlan = this.state.invitation.tag === "auto_created_invitation_for_plan";
|
||||||
|
return (
|
||||||
|
<Card size="small" title={
|
||||||
|
<div>
|
||||||
|
{this.state.mode === "add" ? i18next.t("invitation:New Invitation") : i18next.t("invitation:Edit Invitation")}
|
||||||
|
<Button onClick={() => this.submitInvitationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||||
|
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitInvitationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||||
|
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteInvitation()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||||
|
</div>
|
||||||
|
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||||
|
<Row style={{marginTop: "10px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} disabled={!Setting.isAdminUser(this.props.account) || isCreatedByPlan} value={this.state.invitation.owner} onChange={(value => {this.updateInvitationField("owner", value);})}>
|
||||||
|
{
|
||||||
|
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.name} disabled={isCreatedByPlan} onChange={e => {
|
||||||
|
this.updateInvitationField("name", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.displayName} onChange={e => {
|
||||||
|
this.updateInvitationField("displayName", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("invitation:Code"), i18next.t("invitation:Code - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.code} onChange={e => {
|
||||||
|
this.updateInvitationField("code", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("invitation:Quota"), i18next.t("invitation:Quota - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<InputNumber min={0} value={this.state.invitation.quota} onChange={value => {
|
||||||
|
this.updateInvitationField("quota", value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("invitation:Used count"), i18next.t("invitation:Used count - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<InputNumber min={0} max={this.state.invitation.quota} value={this.state.invitation.usedCount} onChange={value => {
|
||||||
|
this.updateInvitationField("usedCount", value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Application"), i18next.t("general:Application - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.invitation.application}
|
||||||
|
onChange={(value => {this.updateInvitationField("application", value);})}
|
||||||
|
options={this.state.applications.map((application) => Setting.getOption(application.name, application.name))
|
||||||
|
} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.username} onChange={e => {
|
||||||
|
this.updateInvitationField("username", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.email} onChange={e => {
|
||||||
|
this.updateInvitationField("email", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.invitation.phone} onChange={e => {
|
||||||
|
this.updateInvitationField("phone", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:State"), i18next.t("general:State - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.invitation.state} onChange={(value => {
|
||||||
|
this.updateInvitationField("state", value);
|
||||||
|
})}
|
||||||
|
options={[
|
||||||
|
{value: "Active", name: i18next.t("subscription:Active")},
|
||||||
|
{value: "Suspended", name: i18next.t("subscription:Suspended")},
|
||||||
|
].map((item) => Setting.getOption(item.name, item.value))}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitInvitationEdit(exitAfterSave) {
|
||||||
|
const invitation = Setting.deepCopy(this.state.invitation);
|
||||||
|
InvitationBackend.updateInvitation(this.state.organizationName, this.state.invitationName, invitation)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||||
|
this.setState({
|
||||||
|
invitationName: this.state.invitation.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exitAfterSave) {
|
||||||
|
this.props.history.push("/invitations");
|
||||||
|
} else {
|
||||||
|
this.props.history.push(`/invitations/${this.state.invitation.owner}/${this.state.invitation.name}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||||
|
this.updateInvitationField("name", this.state.invitationName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteInvitation() {
|
||||||
|
InvitationBackend.deleteInvitation(this.state.invitation)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.props.history.push("/invitations");
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
this.state.invitation !== null ? this.renderInvitation() : null
|
||||||
|
}
|
||||||
|
<div style={{marginTop: "20px", marginLeft: "40px"}}>
|
||||||
|
<Button size="large" onClick={() => this.submitInvitationEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||||
|
<Button style={{marginLeft: "20px"}} type="primary" size="large" onClick={() => this.submitInvitationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||||
|
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} size="large" onClick={() => this.deleteInvitation()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InvitationEditPage;
|
310
web/src/InvitationListPage.js
Normal file
310
web/src/InvitationListPage.js
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {Button, Table} from "antd";
|
||||||
|
import {MinusCircleOutlined, SyncOutlined} from "@ant-design/icons";
|
||||||
|
import moment from "moment";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import * as InvitationBackend from "./backend/InvitationBackend";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import BaseListPage from "./BaseListPage";
|
||||||
|
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
|
class InvitationListPage extends BaseListPage {
|
||||||
|
newInvitation() {
|
||||||
|
const randomName = Setting.getRandomName();
|
||||||
|
const owner = Setting.getRequestOrganization(this.props.account);
|
||||||
|
return {
|
||||||
|
owner: owner,
|
||||||
|
name: `invitation_${randomName}`,
|
||||||
|
createdTime: moment().format(),
|
||||||
|
updatedTime: moment().format(),
|
||||||
|
displayName: `New Invitation - ${randomName}`,
|
||||||
|
code: Math.random().toString(36).slice(-10),
|
||||||
|
quota: 1,
|
||||||
|
usedCount: 0,
|
||||||
|
application: "",
|
||||||
|
username: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
signupGroup: "",
|
||||||
|
state: "Active",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addInvitation() {
|
||||||
|
const newInvitation = this.newInvitation();
|
||||||
|
InvitationBackend.addInvitation(newInvitation)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.props.history.push({pathname: `/invitations/${newInvitation.owner}/${newInvitation.name}`, mode: "add"});
|
||||||
|
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteInvitation(i) {
|
||||||
|
InvitationBackend.deleteInvitation(this.state.data[i])
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||||
|
this.setState({
|
||||||
|
data: Setting.deleteRow(this.state.data, i),
|
||||||
|
pagination: {total: this.state.pagination.total - 1},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(invitations) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Name"),
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
width: "140px",
|
||||||
|
fixed: "left",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("name"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/invitations/${record.owner}/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Organization"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
width: "150px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("owner"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/organizations/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: i18next.t("general:Created time"),
|
||||||
|
// dataIndex: "createdTime",
|
||||||
|
// key: "createdTime",
|
||||||
|
// width: "160px",
|
||||||
|
// sorter: true,
|
||||||
|
// render: (text, record, index) => {
|
||||||
|
// return Setting.getFormattedDate(text);
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Updated time"),
|
||||||
|
dataIndex: "updatedTime",
|
||||||
|
key: "updatedTime",
|
||||||
|
width: "160px",
|
||||||
|
sorter: true,
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return Setting.getFormattedDate(text);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Display name"),
|
||||||
|
dataIndex: "displayName",
|
||||||
|
key: "displayName",
|
||||||
|
width: "170px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("displayName"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("invitation:Code"),
|
||||||
|
dataIndex: "code",
|
||||||
|
key: "code",
|
||||||
|
width: "160px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("code"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("invitation:Quota"),
|
||||||
|
dataIndex: "quota",
|
||||||
|
key: "quota",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("quota"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("invitation:Used count"),
|
||||||
|
dataIndex: "usedCount",
|
||||||
|
key: "usedCount",
|
||||||
|
width: "130px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("usedCount"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Application"),
|
||||||
|
dataIndex: "application",
|
||||||
|
key: "application",
|
||||||
|
width: "170px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("application"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/applications/${record.owner}/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Email"),
|
||||||
|
dataIndex: "email",
|
||||||
|
key: "email",
|
||||||
|
width: "160px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("email"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<a href={`mailto:${text}`}>
|
||||||
|
{text}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Phone"),
|
||||||
|
dataIndex: "phone",
|
||||||
|
key: "phone",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("phone"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:State"),
|
||||||
|
dataIndex: "state",
|
||||||
|
key: "state",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("state"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
switch (text) {
|
||||||
|
case "Active":
|
||||||
|
return Setting.getTag("success", i18next.t("subscription:Active"), <SyncOutlined spin />);
|
||||||
|
case "Suspended":
|
||||||
|
return Setting.getTag("default", i18next.t("subscription:Suspended"), <MinusCircleOutlined />);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Action"),
|
||||||
|
dataIndex: "",
|
||||||
|
key: "op",
|
||||||
|
width: "350px",
|
||||||
|
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => {
|
||||||
|
copy(`${window.location.origin}/login/${record.owner}?invitation_code=${record.code}`);
|
||||||
|
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||||
|
}}>
|
||||||
|
{i18next.t("application:Copy signup page URL")}
|
||||||
|
</Button>
|
||||||
|
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/invitations/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||||
|
<PopconfirmModal
|
||||||
|
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
||||||
|
onConfirm={() => this.deleteInvitation(index)}
|
||||||
|
>
|
||||||
|
</PopconfirmModal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const paginationProps = {
|
||||||
|
total: this.state.pagination.total,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={invitations} rowKey={(record) => `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps}
|
||||||
|
title={() => (
|
||||||
|
<div>
|
||||||
|
{i18next.t("general:Invitations")}
|
||||||
|
<Button type="primary" size="small" onClick={this.addInvitation.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
loading={this.state.loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
let field = params.searchedColumn, value = params.searchText;
|
||||||
|
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||||
|
if (params.type !== undefined && params.type !== null) {
|
||||||
|
field = "type";
|
||||||
|
value = params.type;
|
||||||
|
}
|
||||||
|
this.setState({loading: true});
|
||||||
|
InvitationBackend.getInvitations(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.setState({
|
||||||
|
data: res.data,
|
||||||
|
pagination: {
|
||||||
|
...params.pagination,
|
||||||
|
total: res.data2,
|
||||||
|
},
|
||||||
|
searchText: params.searchText,
|
||||||
|
searchedColumn: params.searchedColumn,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (Setting.isResponseDenied(res)) {
|
||||||
|
this.setState({
|
||||||
|
isAuthorized: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", res.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InvitationListPage;
|
@@ -393,7 +393,7 @@ class OrganizationEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={22} style={{marginTop: "5px"}}>
|
<Col span={22} style={{marginTop: "5px"}}>
|
||||||
<Row>
|
<Row>
|
||||||
<Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
|
<Radio.Group buttonStyle="solid" value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
|
||||||
const {_, ...theme} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
|
const {_, ...theme} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
|
||||||
this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value});
|
this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value});
|
||||||
}} >
|
}} >
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user