mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-07 05:17:48 +08:00
Compare commits
95 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bc8e9cfd64 | ||
![]() |
c1eae9fcd8 | ||
![]() |
6dae6e4954 | ||
![]() |
559a91e8ee | ||
![]() |
b0aaf09ef1 | ||
![]() |
7e2f67c49a | ||
![]() |
e584a6a111 | ||
![]() |
6700d2e244 | ||
![]() |
0c5c308071 | ||
![]() |
0b859197da | ||
![]() |
3078409343 | ||
![]() |
bbf2db2e00 | ||
![]() |
0c7b911ce7 | ||
![]() |
2cc55715ac | ||
![]() |
c829bf1769 | ||
![]() |
ec956c12ca | ||
![]() |
d3d4646c56 | ||
![]() |
669ac7c618 | ||
![]() |
6715efd781 | ||
![]() |
953be4a7b6 | ||
![]() |
943cc43427 | ||
![]() |
1e5ce7a045 | ||
![]() |
7a85b74573 | ||
![]() |
7e349c1768 | ||
![]() |
b19be2df88 | ||
![]() |
fc3866db1c | ||
![]() |
bf2bb31e41 | ||
![]() |
ec8bd6f01d | ||
![]() |
98722fd681 | ||
![]() |
221c55aa93 | ||
![]() |
988b26b3c2 | ||
![]() |
7e3c361ce7 | ||
![]() |
a637707e77 | ||
![]() |
7970edeaa7 | ||
![]() |
9da2f0775f | ||
![]() |
739a9bcd0d | ||
![]() |
fb0949b9ed | ||
![]() |
27ed901167 | ||
![]() |
ceab662b88 | ||
![]() |
05b2f00057 | ||
![]() |
8073dfa88c | ||
![]() |
1eeeb64a0c | ||
![]() |
f5e0461cae | ||
![]() |
a0c5eb241f | ||
![]() |
4d8edcc446 | ||
![]() |
2b23c04f49 | ||
![]() |
e60ee52d91 | ||
![]() |
c54b54ca19 | ||
![]() |
f0e097e138 | ||
![]() |
25ec1bdfa8 | ||
![]() |
ea7718d7b7 | ||
![]() |
463fa8b636 | ||
![]() |
11895902f4 | ||
![]() |
15269d3315 | ||
![]() |
4468859795 | ||
![]() |
914128a78a | ||
![]() |
e5a189e0f4 | ||
![]() |
a07216d0e1 | ||
![]() |
fec54944dd | ||
![]() |
a2db61cc1a | ||
![]() |
134541acde | ||
![]() |
59fca0342e | ||
![]() |
abfc464155 | ||
![]() |
a41f6880a2 | ||
![]() |
d12117324c | ||
![]() |
1a6c9fbf69 | ||
![]() |
dd60d79af9 | ||
![]() |
73d314c7fe | ||
![]() |
27959e0f6f | ||
![]() |
47f40c5b24 | ||
![]() |
2ff9020884 | ||
![]() |
abaf4ca8d9 | ||
![]() |
8ff0cfd6ec | ||
![]() |
7a2a40edcc | ||
![]() |
b7a001ea39 | ||
![]() |
891e8e21d8 | ||
![]() |
80b0d26813 | ||
![]() |
db4ac60bb6 | ||
![]() |
33a922f026 | ||
![]() |
9f65053d04 | ||
![]() |
be969e5efa | ||
![]() |
9156bd426b | ||
![]() |
fe4a4328aa | ||
![]() |
9899022bcd | ||
![]() |
1a9d02be46 | ||
![]() |
eafaa135b4 | ||
![]() |
6746551447 | ||
![]() |
3cb46c3628 | ||
![]() |
558bcf95d6 | ||
![]() |
bb937c30c1 | ||
![]() |
8dfdf7f767 | ||
![]() |
62b2082e82 | ||
![]() |
a1806439f8 | ||
![]() |
01e58158b7 | ||
![]() |
15427ad9d6 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -110,7 +110,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
start: yarn start
|
start: yarn start
|
||||||
wait-on: 'http://localhost:7001'
|
wait-on: 'http://localhost:7001'
|
||||||
wait-on-timeout: 180
|
wait-on-timeout: 210
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
|
10
README.md
10
README.md
@@ -11,7 +11,7 @@
|
|||||||
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
|
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/releases/latest">
|
<a href="https://github.com/casdoor/casdoor/releases/latest">
|
||||||
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
|
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
|
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
|
||||||
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
|
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
|
||||||
@@ -23,16 +23,16 @@
|
|||||||
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
|
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
|
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
|
||||||
<img src="https://img.shields.io/github/license/casbin/casdoor?style=flat-square" alt="license">
|
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/issues">
|
<a href="https://github.com/casdoor/casdoor/issues">
|
||||||
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casbin/casdoor?style=flat-square">
|
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casbin/casdoor?style=flat-square">
|
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/network">
|
<a href="https://github.com/casdoor/casdoor/network">
|
||||||
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casbin/casdoor?style=flat-square">
|
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://crowdin.com/project/casdoor-site">
|
<a href="https://crowdin.com/project/casdoor-site">
|
||||||
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
|
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
|
||||||
|
@@ -27,13 +27,7 @@ import (
|
|||||||
var Enforcer *casbin.Enforcer
|
var Enforcer *casbin.Enforcer
|
||||||
|
|
||||||
func InitApi() {
|
func InitApi() {
|
||||||
var err error
|
e, err := object.GetInitializedEnforcer(util.GetId("built-in", "api-enforcer-built-in"))
|
||||||
|
|
||||||
e, err := object.GetEnforcer(util.GetId("built-in", "api-enforcer-built-in"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
err = e.InitEnforcer()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -93,6 +87,7 @@ p, *, *, GET, /api/get-prometheus-info, *, *
|
|||||||
p, *, *, *, /api/metrics, *, *
|
p, *, *, *, /api/metrics, *, *
|
||||||
p, *, *, GET, /api/get-pricing, *, *
|
p, *, *, GET, /api/get-pricing, *, *
|
||||||
p, *, *, GET, /api/get-plan, *, *
|
p, *, *, GET, /api/get-plan, *, *
|
||||||
|
p, *, *, GET, /api/get-subscription, *, *
|
||||||
p, *, *, GET, /api/get-organization-names, *, *
|
p, *, *, GET, /api/get-organization-names, *, *
|
||||||
`
|
`
|
||||||
|
|
||||||
|
28
conf/conf.go
28
conf/conf.go
@@ -15,7 +15,7 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -24,15 +24,6 @@ import (
|
|||||||
"github.com/beego/beego"
|
"github.com/beego/beego"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Quota struct {
|
|
||||||
Organization int `json:"organization"`
|
|
||||||
User int `json:"user"`
|
|
||||||
Application int `json:"application"`
|
|
||||||
Provider int `json:"provider"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var quota = &Quota{-1, -1, -1, -1}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// this array contains the beego configuration items that may be modified via env
|
// this array contains the beego configuration items that may be modified via env
|
||||||
presetConfigItems := []string{"httpport", "appname"}
|
presetConfigItems := []string{"httpport", "appname"}
|
||||||
@@ -44,17 +35,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initQuota()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initQuota() {
|
|
||||||
res := beego.AppConfig.String("quota")
|
|
||||||
if res != "" {
|
|
||||||
err := json.Unmarshal([]byte(res), quota)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigString(key string) string {
|
func GetConfigString(key string) string {
|
||||||
@@ -67,7 +47,7 @@ func GetConfigString(key string) string {
|
|||||||
if key == "staticBaseUrl" {
|
if key == "staticBaseUrl" {
|
||||||
res = "https://cdn.casbin.org"
|
res = "https://cdn.casbin.org"
|
||||||
} else if key == "logConfig" {
|
} else if key == "logConfig" {
|
||||||
res = "{\"filename\": \"logs/casdoor.log\", \"maxdays\":99999, \"perm\":\"0770\"}"
|
res = fmt.Sprintf("{\"filename\": \"logs/%s.log\", \"maxdays\":99999, \"perm\":\"0770\"}", beego.AppConfig.String("appname"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,10 +109,6 @@ func GetConfigBatchSize() int {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigQuota() *Quota {
|
|
||||||
return quota
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfigRealDataSourceName(driverName string) string {
|
func GetConfigRealDataSourceName(driverName string) string {
|
||||||
var dataSourceName string
|
var dataSourceName string
|
||||||
if driverName != "mysql" {
|
if driverName != "mysql" {
|
||||||
|
48
conf/conf_quota.go
Normal file
48
conf/conf_quota.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// 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 conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/beego/beego"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Quota struct {
|
||||||
|
Organization int `json:"organization"`
|
||||||
|
User int `json:"user"`
|
||||||
|
Application int `json:"application"`
|
||||||
|
Provider int `json:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var quota = &Quota{-1, -1, -1, -1}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initQuota()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initQuota() {
|
||||||
|
res := beego.AppConfig.String("quota")
|
||||||
|
if res != "" {
|
||||||
|
err := json.Unmarshal([]byte(res), quota)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfigQuota() *Quota {
|
||||||
|
return quota
|
||||||
|
}
|
@@ -140,25 +140,28 @@ func (c *ApiController) Signup() {
|
|||||||
username = id
|
username = id
|
||||||
}
|
}
|
||||||
|
|
||||||
password := authForm.Password
|
|
||||||
msg = object.CheckPasswordComplexityByOrg(organization, password)
|
|
||||||
if msg != "" {
|
|
||||||
c.ResponseError(msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
initScore, err := organization.GetInitScore()
|
initScore, err := organization.GetInitScore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userType := "normal-user"
|
||||||
|
if authForm.Plan != "" && authForm.Pricing != "" {
|
||||||
|
err = object.CheckPricingAndPlan(authForm.Organization, authForm.Pricing, authForm.Plan)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userType = "paid-user"
|
||||||
|
}
|
||||||
|
|
||||||
user := &object.User{
|
user := &object.User{
|
||||||
Owner: authForm.Organization,
|
Owner: authForm.Organization,
|
||||||
Name: username,
|
Name: username,
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
Id: id,
|
Id: id,
|
||||||
Type: "normal-user",
|
Type: userType,
|
||||||
Password: authForm.Password,
|
Password: authForm.Password,
|
||||||
DisplayName: authForm.Name,
|
DisplayName: authForm.Name,
|
||||||
Avatar: organization.DefaultAvatar,
|
Avatar: organization.DefaultAvatar,
|
||||||
@@ -171,7 +174,6 @@ func (c *ApiController) Signup() {
|
|||||||
Region: authForm.Region,
|
Region: authForm.Region,
|
||||||
Score: initScore,
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
IsDeleted: false,
|
IsDeleted: false,
|
||||||
SignupApplication: application.Name,
|
SignupApplication: application.Name,
|
||||||
@@ -211,7 +213,7 @@ func (c *ApiController) Signup() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.HasPromptPage() {
|
if application.HasPromptPage() && user.Type == "normal-user" {
|
||||||
// The prompt page needs the user to be signed in
|
// The prompt page needs the user to be signed in
|
||||||
c.SetSessionUsername(user.GetId())
|
c.SetSessionUsername(user.GetId())
|
||||||
}
|
}
|
||||||
@@ -228,15 +230,6 @@ func (c *ApiController) Signup() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isSignupFromPricing := authForm.Plan != "" && authForm.Pricing != ""
|
|
||||||
if isSignupFromPricing {
|
|
||||||
_, err = object.Subscribe(organization.Name, user.Name, authForm.Plan, authForm.Pricing)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
record.User = user.Name
|
record.User = user.Name
|
||||||
|
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetAdapters
|
// GetAdapters
|
||||||
@@ -144,92 +143,3 @@ func (c *ApiController) DeleteAdapter() {
|
|||||||
c.Data["json"] = wrapActionResponse(object.DeleteAdapter(&adapter))
|
c.Data["json"] = wrapActionResponse(object.DeleteAdapter(&adapter))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetPolicies() {
|
|
||||||
id := c.Input().Get("id")
|
|
||||||
adapter, err := object.GetAdapter(id)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
policies, err := object.GetPolicies(adapter)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(policies)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ApiController) UpdatePolicy() {
|
|
||||||
id := c.Input().Get("id")
|
|
||||||
adapter, err := object.GetAdapter(id)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var policies []xormadapter.CasbinRule
|
|
||||||
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
affected, err := object.UpdatePolicy(util.CasbinToSlice(policies[0]), util.CasbinToSlice(policies[1]), adapter)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Data["json"] = wrapActionResponse(affected)
|
|
||||||
c.ServeJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ApiController) AddPolicy() {
|
|
||||||
id := c.Input().Get("id")
|
|
||||||
adapter, err := object.GetAdapter(id)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var policy xormadapter.CasbinRule
|
|
||||||
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
affected, err := object.AddPolicy(util.CasbinToSlice(policy), adapter)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Data["json"] = wrapActionResponse(affected)
|
|
||||||
c.ServeJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ApiController) RemovePolicy() {
|
|
||||||
id := c.Input().Get("id")
|
|
||||||
adapter, err := object.GetAdapter(id)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var policy xormadapter.CasbinRule
|
|
||||||
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
affected, err := object.RemovePolicy(util.CasbinToSlice(policy), adapter)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Data["json"] = wrapActionResponse(affected)
|
|
||||||
c.ServeJSON()
|
|
||||||
}
|
|
||||||
|
@@ -62,13 +62,13 @@ func (c *ApiController) GetApplications() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||||
app, err := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
application, err := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
applications := object.GetMaskedApplications(app, userId)
|
applications := object.GetMaskedApplications(application, userId)
|
||||||
c.ResponseOk(applications, paginator.Nums())
|
c.ResponseOk(applications, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,13 +84,23 @@ func (c *ApiController) GetApplication() {
|
|||||||
userId := c.GetSessionUsername()
|
userId := c.GetSessionUsername()
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
app, err := object.GetApplication(id)
|
application, err := object.GetApplication(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(object.GetMaskedApplication(app, userId))
|
if c.Input().Get("withKey") != "" && application.Cert != "" {
|
||||||
|
cert, err := object.GetCert(util.GetId(application.Owner, application.Cert))
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
application.CertPublicKey = cert.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(object.GetMaskedApplication(application, userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserApplication
|
// GetUserApplication
|
||||||
@@ -164,13 +174,13 @@ func (c *ApiController) GetOrganizationApplications() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||||
app, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
application, err := object.GetPaginationOrganizationApplications(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
|
||||||
}
|
}
|
||||||
|
|
||||||
applications := object.GetMaskedApplications(app, userId)
|
applications := object.GetMaskedApplications(application, userId)
|
||||||
c.ResponseOk(applications, paginator.Nums())
|
c.ResponseOk(applications, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -70,7 +70,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check user's tag
|
// check user's tag
|
||||||
if !user.IsGlobalAdmin && !user.IsAdmin && len(application.Tags) > 0 {
|
if !user.IsGlobalAdmin() && !user.IsAdmin && len(application.Tags) > 0 {
|
||||||
// only users with the tag that is listed in the application tags can login
|
// only users with the tag that is listed in the application tags can login
|
||||||
if !util.InSlice(application.Tags, user.Tag) {
|
if !util.InSlice(application.Tags, user.Tag) {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:User's tag: %s is not listed in the application's tags"), user.Tag))
|
c.ResponseError(fmt.Sprintf(c.T("auth:User's tag: %s is not listed in the application's tags"), user.Tag))
|
||||||
@@ -78,6 +78,46 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check whether paid-user have active subscription
|
||||||
|
if user.Type == "paid-user" {
|
||||||
|
subscriptions, err := object.GetSubscriptionsByUser(user.Owner, user.Name)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
existActiveSubscription := false
|
||||||
|
for _, subscription := range subscriptions {
|
||||||
|
if subscription.State == object.SubStateActive {
|
||||||
|
existActiveSubscription = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !existActiveSubscription {
|
||||||
|
// check pending subscription
|
||||||
|
for _, sub := range subscriptions {
|
||||||
|
if sub.State == object.SubStatePending {
|
||||||
|
c.ResponseOk("BuyPlanResult", sub)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// paid-user does not have active or pending subscription, find the default pricing of application
|
||||||
|
pricing, err := object.GetApplicationDefaultPricing(application.Organization, application.Name)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pricing == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"), user.Name, application.Name))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// let the paid-user select plan
|
||||||
|
c.ResponseOk("SelectPlan", pricing)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if form.Type == ResponseTypeLogin {
|
if form.Type == ResponseTypeLogin {
|
||||||
c.SetSessionUsername(userId)
|
c.SetSessionUsername(userId)
|
||||||
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
||||||
@@ -187,11 +227,34 @@ func (c *ApiController) GetApplicationLogin() {
|
|||||||
redirectUri := c.Input().Get("redirectUri")
|
redirectUri := c.Input().Get("redirectUri")
|
||||||
scope := c.Input().Get("scope")
|
scope := c.Input().Get("scope")
|
||||||
state := c.Input().Get("state")
|
state := c.Input().Get("state")
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
loginType := c.Input().Get("type")
|
||||||
|
|
||||||
msg, application, err := object.CheckOAuthLogin(clientId, responseType, redirectUri, scope, state, c.GetAcceptLanguage())
|
var application *object.Application
|
||||||
if err != nil {
|
var msg string
|
||||||
c.ResponseError(err.Error())
|
var err error
|
||||||
return
|
if loginType == "code" {
|
||||||
|
msg, application, err = object.CheckOAuthLogin(clientId, responseType, redirectUri, scope, state, c.GetAcceptLanguage())
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if loginType == "cas" {
|
||||||
|
application, err = object.GetApplication(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if application == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), id))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = object.CheckCasLogin(application, c.GetAcceptLanguage(), redirectUri)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
application = object.GetMaskedApplication(application, "")
|
application = object.GetMaskedApplication(application, "")
|
||||||
@@ -566,7 +629,6 @@ func (c *ApiController) Login() {
|
|||||||
Region: userInfo.CountryCode,
|
Region: userInfo.CountryCode,
|
||||||
Score: initScore,
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
IsDeleted: false,
|
IsDeleted: false,
|
||||||
SignupApplication: application.Name,
|
SignupApplication: application.Name,
|
||||||
|
@@ -61,6 +61,10 @@ func (c *ApiController) IsAdminOrSelf(user2 *object.User) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user == nil || user2 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if user.Owner == user2.Owner && user.Name == user2.Name {
|
if user.Owner == user2.Owner && user.Name == user2.Name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,7 @@ func (c *ApiController) isGlobalAdmin() (bool, *object.User) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.Owner == "built-in" || user.IsGlobalAdmin, user
|
return user.IsGlobalAdmin(), user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) getCurrentUser() *object.User {
|
func (c *ApiController) getCurrentUser() *object.User {
|
||||||
|
@@ -35,6 +35,11 @@ const (
|
|||||||
UnauthorizedService string = "UNAUTHORIZED_SERVICE"
|
UnauthorizedService string = "UNAUTHORIZED_SERVICE"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func queryUnescape(service string) string {
|
||||||
|
s, _ := url.QueryUnescape(service)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RootController) CasValidate() {
|
func (c *RootController) CasValidate() {
|
||||||
ticket := c.Input().Get("ticket")
|
ticket := c.Input().Get("ticket")
|
||||||
service := c.Input().Get("service")
|
service := c.Input().Get("service")
|
||||||
@@ -60,24 +65,25 @@ func (c *RootController) CasServiceValidate() {
|
|||||||
if !strings.HasPrefix(ticket, "ST") {
|
if !strings.HasPrefix(ticket, "ST") {
|
||||||
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
||||||
}
|
}
|
||||||
c.CasP3ServiceAndProxyValidate()
|
c.CasP3ProxyValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RootController) CasProxyValidate() {
|
func (c *RootController) CasProxyValidate() {
|
||||||
|
// https://apereo.github.io/cas/6.6.x/protocol/CAS-Protocol-Specification.html#26-proxyvalidate-cas-20
|
||||||
|
// "/proxyValidate" should accept both service tickets and proxy tickets.
|
||||||
|
c.CasP3ProxyValidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RootController) CasP3ServiceValidate() {
|
||||||
ticket := c.Input().Get("ticket")
|
ticket := c.Input().Get("ticket")
|
||||||
format := c.Input().Get("format")
|
format := c.Input().Get("format")
|
||||||
if !strings.HasPrefix(ticket, "PT") {
|
if !strings.HasPrefix(ticket, "ST") {
|
||||||
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
||||||
}
|
}
|
||||||
c.CasP3ServiceAndProxyValidate()
|
c.CasP3ProxyValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryUnescape(service string) string {
|
func (c *RootController) CasP3ProxyValidate() {
|
||||||
s, _ := url.QueryUnescape(service)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *RootController) CasP3ServiceAndProxyValidate() {
|
|
||||||
ticket := c.Input().Get("ticket")
|
ticket := c.Input().Get("ticket")
|
||||||
format := c.Input().Get("format")
|
format := c.Input().Get("format")
|
||||||
service := c.Input().Get("service")
|
service := c.Input().Get("service")
|
||||||
@@ -115,15 +121,17 @@ func (c *RootController) CasP3ServiceAndProxyValidate() {
|
|||||||
pgtiou := serviceResponse.Success.ProxyGrantingTicket
|
pgtiou := serviceResponse.Success.ProxyGrantingTicket
|
||||||
// todo: check whether it is https
|
// todo: check whether it is https
|
||||||
pgtUrlObj, err := url.Parse(pgtUrl)
|
pgtUrlObj, err := url.Parse(pgtUrl)
|
||||||
|
if err != nil {
|
||||||
|
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, err.Error(), format)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if pgtUrlObj.Scheme != "https" {
|
if pgtUrlObj.Scheme != "https" {
|
||||||
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, "callback is not https", format)
|
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, "callback is not https", format)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a request to pgturl passing pgt and pgtiou
|
// make a request to pgturl passing pgt and pgtiou
|
||||||
if err != nil {
|
|
||||||
c.sendCasAuthenticationResponseErr(InternalError, err.Error(), format)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
param := pgtUrlObj.Query()
|
param := pgtUrlObj.Query()
|
||||||
param.Add("pgtId", pgt)
|
param.Add("pgtId", pgt)
|
||||||
param.Add("pgtIou", pgtiou)
|
param.Add("pgtIou", pgtiou)
|
||||||
@@ -263,7 +271,6 @@ func (c *RootController) sendCasAuthenticationResponseErr(code, msg, format stri
|
|||||||
Message: msg,
|
Message: msg,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if format == "json" {
|
if format == "json" {
|
||||||
c.Data["json"] = serviceResponse
|
c.Data["json"] = serviceResponse
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
|
@@ -45,13 +45,7 @@ func (c *ApiController) Enforce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if enforcerId != "" {
|
if enforcerId != "" {
|
||||||
enforcer, err := object.GetEnforcer(enforcerId)
|
enforcer, err := object.GetInitializedEnforcer(enforcerId)
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = enforcer.InitEnforcer()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -155,13 +149,7 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if enforcerId != "" {
|
if enforcerId != "" {
|
||||||
enforcer, err := object.GetEnforcer(enforcerId)
|
enforcer, err := object.GetInitializedEnforcer(enforcerId)
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = enforcer.InitEnforcer()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
|
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetEnforcers
|
// GetEnforcers
|
||||||
@@ -74,6 +75,7 @@ func (c *ApiController) GetEnforcers() {
|
|||||||
// @router /get-enforcer [get]
|
// @router /get-enforcer [get]
|
||||||
func (c *ApiController) GetEnforcer() {
|
func (c *ApiController) GetEnforcer() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
|
loadModelCfg := c.Input().Get("loadModelCfg")
|
||||||
|
|
||||||
enforcer, err := object.GetEnforcer(id)
|
enforcer, err := object.GetEnforcer(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -81,6 +83,13 @@ func (c *ApiController) GetEnforcer() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if loadModelCfg == "true" && enforcer.Model != "" {
|
||||||
|
err := enforcer.LoadModelCfg()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.ResponseOk(enforcer)
|
c.ResponseOk(enforcer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,3 +152,88 @@ func (c *ApiController) DeleteEnforcer() {
|
|||||||
c.Data["json"] = wrapActionResponse(object.DeleteEnforcer(&enforcer))
|
c.Data["json"] = wrapActionResponse(object.DeleteEnforcer(&enforcer))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) GetPolicies() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
adapterId := c.Input().Get("adapterId")
|
||||||
|
|
||||||
|
if adapterId != "" {
|
||||||
|
adapter, err := object.GetAdapter(adapterId)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = adapter.InitAdapter()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.ResponseOk()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
policies, err := object.GetPolicies(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(policies)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) UpdatePolicy() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var policies []xormadapter.CasbinRule
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := object.UpdatePolicy(id, util.CasbinToSlice(policies[0]), util.CasbinToSlice(policies[1]))
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Data["json"] = wrapActionResponse(affected)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) AddPolicy() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var policy xormadapter.CasbinRule
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := object.AddPolicy(id, util.CasbinToSlice(policy))
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Data["json"] = wrapActionResponse(affected)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) RemovePolicy() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var policy xormadapter.CasbinRule
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := object.RemovePolicy(id, util.CasbinToSlice(policy))
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Data["json"] = wrapActionResponse(affected)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
35
controllers/get-dashboard.go
Normal file
35
controllers/get-dashboard.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// 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 "github.com/casdoor/casdoor/object"
|
||||||
|
|
||||||
|
// GetDashboard
|
||||||
|
// @Title GetDashboard
|
||||||
|
// @Tag GetDashboard API
|
||||||
|
// @Description get information of dashboard
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /get-dashboard [get]
|
||||||
|
func (c *ApiController) GetDashboard() {
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
|
||||||
|
data, err := object.GetDashboard(owner)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(data)
|
||||||
|
}
|
@@ -45,13 +45,13 @@ func (c *ApiController) Unlink() {
|
|||||||
// the user will be unlinked from the provider
|
// the user will be unlinked from the provider
|
||||||
unlinkedUser := form.User
|
unlinkedUser := form.User
|
||||||
|
|
||||||
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
|
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin() {
|
||||||
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
|
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
|
||||||
c.ResponseError(c.T("link:You are not the global admin, you can't unlink other users"))
|
c.ResponseError(c.T("link:You are not the global admin, you can't unlink other users"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin {
|
if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin() {
|
||||||
// if the user is unlinking themselves, should check the provider can be unlinked, if not, we should return an error.
|
// if the user is unlinking themselves, should check the provider can be unlinked, if not, we should return an error.
|
||||||
application, err := object.GetApplicationByUser(user)
|
application, err := object.GetApplicationByUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -183,8 +183,6 @@ func (c *ApiController) DeleteOrganization() {
|
|||||||
func (c *ApiController) GetDefaultApplication() {
|
func (c *ApiController) GetDefaultApplication() {
|
||||||
userId := c.GetSessionUsername()
|
userId := c.GetSessionUsername()
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
redirectUri := c.Input().Get("redirectUri")
|
|
||||||
typ := c.Input().Get("type")
|
|
||||||
|
|
||||||
application, err := object.GetDefaultApplication(id)
|
application, err := object.GetDefaultApplication(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -192,14 +190,6 @@ func (c *ApiController) GetDefaultApplication() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if typ == "cas" {
|
|
||||||
err = object.CheckCasRestrict(application, c.GetAcceptLanguage(), redirectUri)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maskedApplication := object.GetMaskedApplication(application, userId)
|
maskedApplication := object.GetMaskedApplication(application, userId)
|
||||||
c.ResponseOk(maskedApplication)
|
c.ResponseOk(maskedApplication)
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@@ -32,16 +33,15 @@ func (c *ApiController) UploadPermissions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
|
|
||||||
path := util.GetUploadXlsxPath(fileId)
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
util.EnsureFileFolderExists(path)
|
defer os.Remove(path)
|
||||||
err = saveFile(path, &file)
|
err = saveFile(path, &file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := object.UploadPermissions(owner, fileId)
|
affected, err := object.UploadPermissions(owner, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@@ -82,7 +83,10 @@ func (c *ApiController) GetPlan() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if plan == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("plan:The plan: %s does not exist"), id))
|
||||||
|
return
|
||||||
|
}
|
||||||
if includeOption {
|
if includeOption {
|
||||||
options, err := object.GetPermissionsByRole(plan.Role)
|
options, err := object.GetPermissionsByRole(plan.Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,14 +114,29 @@ func (c *ApiController) GetPlan() {
|
|||||||
// @router /update-plan [post]
|
// @router /update-plan [post]
|
||||||
func (c *ApiController) UpdatePlan() {
|
func (c *ApiController) UpdatePlan() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
|
owner := util.GetOwnerFromId(id)
|
||||||
var plan object.Plan
|
var plan object.Plan
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if plan.Product != "" {
|
||||||
|
productId := util.GetId(owner, plan.Product)
|
||||||
|
product, err := object.GetProduct(productId)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if product != nil {
|
||||||
|
object.UpdateProductForPlan(&plan, product)
|
||||||
|
_, err = object.UpdateProduct(productId, product)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdatePlan(id, &plan))
|
c.Data["json"] = wrapActionResponse(object.UpdatePlan(id, &plan))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
@@ -136,7 +155,14 @@ func (c *ApiController) AddPlan() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Create a related product for plan
|
||||||
|
product := object.CreateProductForPlan(&plan)
|
||||||
|
_, err = object.AddProduct(product)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
plan.Product = product.Name
|
||||||
c.Data["json"] = wrapActionResponse(object.AddPlan(&plan))
|
c.Data["json"] = wrapActionResponse(object.AddPlan(&plan))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
@@ -155,7 +181,13 @@ func (c *ApiController) DeletePlan() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if plan.Product != "" {
|
||||||
|
_, err = object.DeleteProduct(&object.Product{Owner: plan.Owner, Name: plan.Product})
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
c.Data["json"] = wrapActionResponse(object.DeletePlan(&plan))
|
c.Data["json"] = wrapActionResponse(object.DeletePlan(&plan))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@@ -80,7 +81,10 @@ func (c *ApiController) GetPricing() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if pricing == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("pricing:The pricing: %s does not exist"), id))
|
||||||
|
return
|
||||||
|
}
|
||||||
c.ResponseOk(pricing)
|
c.ResponseOk(pricing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -161,10 +161,17 @@ func (c *ApiController) DeleteProduct() {
|
|||||||
// @router /buy-product [post]
|
// @router /buy-product [post]
|
||||||
func (c *ApiController) BuyProduct() {
|
func (c *ApiController) BuyProduct() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
providerName := c.Input().Get("providerName")
|
|
||||||
host := c.Ctx.Request.Host
|
host := c.Ctx.Request.Host
|
||||||
|
providerName := c.Input().Get("providerName")
|
||||||
userId := c.GetSessionUsername()
|
// buy `pricingName/planName` for `paidUserName`
|
||||||
|
pricingName := c.Input().Get("pricingName")
|
||||||
|
planName := c.Input().Get("planName")
|
||||||
|
paidUserName := c.Input().Get("userName")
|
||||||
|
owner, _ := util.GetOwnerAndNameFromId(id)
|
||||||
|
userId := util.GetId(owner, paidUserName)
|
||||||
|
if paidUserName == "" {
|
||||||
|
userId = c.GetSessionUsername()
|
||||||
|
}
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
c.ResponseError(c.T("general:Please login first"))
|
c.ResponseError(c.T("general:Please login first"))
|
||||||
return
|
return
|
||||||
@@ -175,13 +182,12 @@ func (c *ApiController) BuyProduct() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
payUrl, orderId, err := object.BuyProduct(id, providerName, user, host)
|
payUrl, orderId, err := object.BuyProduct(id, user, providerName, pricingName, planName, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -1,121 +0,0 @@
|
|||||||
// 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 controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
|
||||||
"github.com/casdoor/casdoor/object"
|
|
||||||
"github.com/casdoor/casdoor/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetRecords
|
|
||||||
// @Title GetRecords
|
|
||||||
// @Tag Record API
|
|
||||||
// @Description get all records
|
|
||||||
// @Param pageSize query string true "The size of each page"
|
|
||||||
// @Param p query string true "The number of the page"
|
|
||||||
// @Success 200 {object} object.Record The Response object
|
|
||||||
// @router /get-records [get]
|
|
||||||
func (c *ApiController) GetRecords() {
|
|
||||||
organization, ok := c.RequireAdmin()
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
limit := c.Input().Get("pageSize")
|
|
||||||
page := c.Input().Get("p")
|
|
||||||
field := c.Input().Get("field")
|
|
||||||
value := c.Input().Get("value")
|
|
||||||
sortField := c.Input().Get("sortField")
|
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
|
||||||
organizationName := c.Input().Get("organizationName")
|
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
|
||||||
records, err := object.GetRecords()
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(records)
|
|
||||||
} else {
|
|
||||||
limit := util.ParseInt(limit)
|
|
||||||
if c.IsGlobalAdmin() && organizationName != "" {
|
|
||||||
organization = organizationName
|
|
||||||
}
|
|
||||||
filterRecord := &object.Record{Organization: organization}
|
|
||||||
count, err := object.GetRecordCount(field, value, filterRecord)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
|
||||||
records, err := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(records, paginator.Nums())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRecordsByFilter
|
|
||||||
// @Tag Record API
|
|
||||||
// @Title GetRecordsByFilter
|
|
||||||
// @Description get records by filter
|
|
||||||
// @Param filter body string true "filter Record message"
|
|
||||||
// @Success 200 {object} object.Record The Response object
|
|
||||||
// @router /get-records-filter [post]
|
|
||||||
func (c *ApiController) GetRecordsByFilter() {
|
|
||||||
body := string(c.Ctx.Input.RequestBody)
|
|
||||||
|
|
||||||
record := &object.Record{}
|
|
||||||
err := util.JsonToStruct(body, record)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
records, err := object.GetRecordsByField(record)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(records)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRecord
|
|
||||||
// @Title AddRecord
|
|
||||||
// @Tag Record API
|
|
||||||
// @Description add a record
|
|
||||||
// @Param body body object.Record true "The details of the record"
|
|
||||||
// @Success 200 {object} controllers.Response The Response object
|
|
||||||
// @router /add-record [post]
|
|
||||||
func (c *ApiController) AddRecord() {
|
|
||||||
var record object.Record
|
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &record)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddRecord(&record))
|
|
||||||
c.ServeJSON()
|
|
||||||
}
|
|
@@ -361,6 +361,9 @@ func (c *ApiController) UploadResource() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.Properties == nil {
|
||||||
|
user.Properties = map[string]string{}
|
||||||
|
}
|
||||||
user.Properties[tag] = fileUrl
|
user.Properties[tag] = fileUrl
|
||||||
user.Properties["isIdCardVerified"] = "false"
|
user.Properties["isIdCardVerified"] = "false"
|
||||||
_, err = object.UpdateUser(user.GetId(), user, []string{"properties"}, false)
|
_, err = object.UpdateUser(user.GetId(), user, []string{"properties"}, false)
|
||||||
|
@@ -16,6 +16,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@@ -32,16 +33,15 @@ func (c *ApiController) UploadRoles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
|
|
||||||
path := util.GetUploadXlsxPath(fileId)
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
util.EnsureFileFolderExists(path)
|
defer os.Remove(path)
|
||||||
err = saveFile(path, &file)
|
err = saveFile(path, &file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := object.UploadRoles(owner, fileId)
|
affected, err := object.UploadRoles(owner, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,10 @@ type SmsForm struct {
|
|||||||
OrgId string `json:"organizationId"` // e.g. "admin/built-in"
|
OrgId string `json:"organizationId"` // e.g. "admin/built-in"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotificationForm struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
// SendEmail
|
// SendEmail
|
||||||
// @Title SendEmail
|
// @Title SendEmail
|
||||||
// @Tag Service API
|
// @Tag Service API
|
||||||
@@ -140,10 +144,12 @@ func (c *ApiController) SendSms() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidReceivers := getInvalidSmsReceivers(smsForm)
|
if provider.Type != "Custom HTTP SMS" {
|
||||||
if len(invalidReceivers) != 0 {
|
invalidReceivers := getInvalidSmsReceivers(smsForm)
|
||||||
c.ResponseError(fmt.Sprintf(c.T("service:Invalid phone receivers: %s"), strings.Join(invalidReceivers, ", ")))
|
if len(invalidReceivers) != 0 {
|
||||||
return
|
c.ResponseError(fmt.Sprintf(c.T("service:Invalid phone receivers: %s"), strings.Join(invalidReceivers, ", ")))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = object.SendSms(provider, smsForm.Content, smsForm.Receivers...)
|
err = object.SendSms(provider, smsForm.Content, smsForm.Receivers...)
|
||||||
@@ -154,3 +160,33 @@ func (c *ApiController) SendSms() {
|
|||||||
|
|
||||||
c.ResponseOk()
|
c.ResponseOk()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendNotification
|
||||||
|
// @Title SendNotification
|
||||||
|
// @Tag Service API
|
||||||
|
// @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"
|
||||||
|
// @Success 200 {object} Response object
|
||||||
|
// @router /api/send-notification [post]
|
||||||
|
func (c *ApiController) SendNotification() {
|
||||||
|
provider, err := c.GetProviderFromContext("Notification")
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var notificationForm NotificationForm
|
||||||
|
err = json.Unmarshal(c.Ctx.Input.RequestBody, ¬ificationForm)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = object.SendNotification(provider, notificationForm.Content)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk()
|
||||||
|
}
|
||||||
|
@@ -160,7 +160,11 @@ func (c *ApiController) RunSyncer() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
object.RunSyncer(syncer)
|
err = object.RunSyncer(syncer)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.ResponseOk()
|
c.ResponseOk()
|
||||||
}
|
}
|
||||||
|
@@ -47,16 +47,16 @@ func (c *ApiController) GetSystemInfo() {
|
|||||||
// @router /get-version-info [get]
|
// @router /get-version-info [get]
|
||||||
func (c *ApiController) GetVersionInfo() {
|
func (c *ApiController) GetVersionInfo() {
|
||||||
versionInfo, err := util.GetVersionInfo()
|
versionInfo, err := util.GetVersionInfo()
|
||||||
|
if versionInfo.Version != "" {
|
||||||
if versionInfo.Version == "" {
|
c.ResponseOk(versionInfo)
|
||||||
versionInfo, err = util.GetVersionInfoFromFile()
|
return
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionInfo, err = util.GetVersionInfoFromFile()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
c.ResponseOk(versionInfo)
|
c.ResponseOk(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -90,7 +90,7 @@ func (c *ApiController) GetUsers() {
|
|||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
if groupName != "" {
|
if groupName != "" {
|
||||||
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(groupName))
|
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -258,6 +258,13 @@ func (c *ApiController) UpdateUser() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Input().Get("allowEmpty") == "" {
|
||||||
|
if user.DisplayName == "" {
|
||||||
|
c.ResponseError(c.T("user:Display name cannot be empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
|
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
|
||||||
c.ResponseError(msg)
|
c.ResponseError(msg)
|
||||||
return
|
return
|
||||||
@@ -441,6 +448,10 @@ func (c *ApiController) SetPassword() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetUser, err := object.GetUser(userId)
|
targetUser, err := object.GetUser(userId)
|
||||||
|
if targetUser == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
|
||||||
|
return
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -567,6 +578,22 @@ func (c *ApiController) RemoveUserFromGroup() {
|
|||||||
name := c.Ctx.Request.Form.Get("name")
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
groupName := c.Ctx.Request.Form.Get("groupName")
|
groupName := c.Ctx.Request.Form.Get("groupName")
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.RemoveUserFromGroup(owner, name, util.GetId(owner, groupName)))
|
organization, err := object.GetOrganization(util.GetId("admin", owner))
|
||||||
c.ServeJSON()
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item := object.GetAccountItemByName("Groups", organization)
|
||||||
|
res, msg := object.CheckAccountItemModifyRule(item, c.IsAdmin(), c.GetAcceptLanguage())
|
||||||
|
if !res {
|
||||||
|
c.ResponseError(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := object.DeleteGroupForUser(util.GetId(owner, name), groupName)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(affected)
|
||||||
}
|
}
|
||||||
|
@@ -48,17 +48,17 @@ func (c *ApiController) UploadUsers() {
|
|||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
|
||||||
|
|
||||||
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
path := util.GetUploadXlsxPath(fileId)
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
util.EnsureFileFolderExists(path)
|
defer os.Remove(path)
|
||||||
err = saveFile(path, &file)
|
err = saveFile(path, &file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := object.UploadUsers(owner, fileId)
|
affected, err := object.UploadUsers(owner, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
|
23
form/auth.go
23
form/auth.go
@@ -17,17 +17,18 @@ package form
|
|||||||
type AuthForm struct {
|
type AuthForm struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
FirstName string `json:"firstName"`
|
FirstName string `json:"firstName"`
|
||||||
LastName string `json:"lastName"`
|
LastName string `json:"lastName"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone"`
|
||||||
Affiliation string `json:"affiliation"`
|
Affiliation string `json:"affiliation"`
|
||||||
IdCard string `json:"idCard"`
|
IdCard string `json:"idCard"`
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
|
InvitationCode string `json:"invitationCode"`
|
||||||
|
|
||||||
Application string `json:"application"`
|
Application string `json:"application"`
|
||||||
ClientId string `json:"clientId"`
|
ClientId string `json:"clientId"`
|
||||||
|
27
go.mod
27
go.mod
@@ -14,8 +14,9 @@ require (
|
|||||||
github.com/casbin/casbin/v2 v2.30.1
|
github.com/casbin/casbin/v2 v2.30.1
|
||||||
github.com/casdoor/go-sms-sender v0.12.0
|
github.com/casdoor/go-sms-sender v0.12.0
|
||||||
github.com/casdoor/gomail/v2 v2.0.1
|
github.com/casdoor/gomail/v2 v2.0.1
|
||||||
github.com/casdoor/oss v1.2.1
|
github.com/casdoor/oss v1.3.0
|
||||||
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
||||||
|
github.com/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
|
||||||
github.com/denisenkom/go-mssqldb v0.9.0
|
github.com/denisenkom/go-mssqldb v0.9.0
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
||||||
@@ -26,34 +27,32 @@ require (
|
|||||||
github.com/go-mysql-org/go-mysql v1.7.0
|
github.com/go-mysql-org/go-mysql v1.7.0
|
||||||
github.com/go-pay/gopay v1.5.72
|
github.com/go-pay/gopay v1.5.72
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||||
github.com/go-webauthn/webauthn v0.6.0
|
github.com/go-webauthn/webauthn v0.6.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/mux v1.7.3 // indirect
|
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||||
github.com/lestrrat-go/jwx v1.2.21
|
github.com/lestrrat-go/jwx v1.2.21
|
||||||
github.com/lib/pq v1.10.2
|
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.75.2
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
|
github.com/nikoksr/notify v0.41.0
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||||
github.com/nyaruka/phonenumbers v1.1.5
|
github.com/nyaruka/phonenumbers v1.1.5
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.11.1
|
github.com/prometheus/client_golang v1.11.1
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.3.0
|
||||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/russellhaering/gosaml2 v0.9.0
|
github.com/russellhaering/gosaml2 v0.9.0
|
||||||
github.com/russellhaering/goxmldsig v1.2.0
|
github.com/russellhaering/goxmldsig v1.2.0
|
||||||
github.com/satori/go.uuid v1.2.0
|
|
||||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/stripe/stripe-go/v74 v74.29.0
|
||||||
github.com/tealeg/xlsx v1.0.5
|
github.com/tealeg/xlsx v1.0.5
|
||||||
github.com/thanhpk/randstr v1.0.4
|
github.com/thanhpk/randstr v1.0.4
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
@@ -61,12 +60,10 @@ require (
|
|||||||
github.com/xorm-io/core v0.7.4
|
github.com/xorm-io/core v0.7.4
|
||||||
github.com/xorm-io/xorm v1.1.6
|
github.com/xorm-io/xorm v1.1.6
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.6.0
|
golang.org/x/crypto v0.11.0
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
golang.org/x/net v0.13.0
|
||||||
golang.org/x/net v0.7.0
|
golang.org/x/oauth2 v0.10.0
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
modernc.org/sqlite v1.18.2
|
||||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
|
||||||
)
|
)
|
||||||
|
@@ -36,6 +36,15 @@ func TestGenerateI18nFrontend(t *testing.T) {
|
|||||||
applyToOtherLanguage("frontend", "it", data)
|
applyToOtherLanguage("frontend", "it", data)
|
||||||
applyToOtherLanguage("frontend", "ms", data)
|
applyToOtherLanguage("frontend", "ms", data)
|
||||||
applyToOtherLanguage("frontend", "tr", data)
|
applyToOtherLanguage("frontend", "tr", data)
|
||||||
|
applyToOtherLanguage("frontend", "ar", data)
|
||||||
|
applyToOtherLanguage("frontend", "he", data)
|
||||||
|
applyToOtherLanguage("frontend", "nl", data)
|
||||||
|
applyToOtherLanguage("frontend", "pl", data)
|
||||||
|
applyToOtherLanguage("frontend", "fi", data)
|
||||||
|
applyToOtherLanguage("frontend", "sv", data)
|
||||||
|
applyToOtherLanguage("frontend", "uk", data)
|
||||||
|
applyToOtherLanguage("frontend", "kk", data)
|
||||||
|
applyToOtherLanguage("frontend", "fa", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateI18nBackend(t *testing.T) {
|
func TestGenerateI18nBackend(t *testing.T) {
|
||||||
@@ -55,4 +64,13 @@ func TestGenerateI18nBackend(t *testing.T) {
|
|||||||
applyToOtherLanguage("backend", "it", data)
|
applyToOtherLanguage("backend", "it", data)
|
||||||
applyToOtherLanguage("backend", "ms", data)
|
applyToOtherLanguage("backend", "ms", data)
|
||||||
applyToOtherLanguage("backend", "tr", data)
|
applyToOtherLanguage("backend", "tr", data)
|
||||||
|
applyToOtherLanguage("backend", "ar", data)
|
||||||
|
applyToOtherLanguage("backend", "he", data)
|
||||||
|
applyToOtherLanguage("backend", "nl", data)
|
||||||
|
applyToOtherLanguage("backend", "pl", data)
|
||||||
|
applyToOtherLanguage("backend", "fi", data)
|
||||||
|
applyToOtherLanguage("backend", "sv", data)
|
||||||
|
applyToOtherLanguage("backend", "uk", data)
|
||||||
|
applyToOtherLanguage("backend", "kk", data)
|
||||||
|
applyToOtherLanguage("backend", "fa", data)
|
||||||
}
|
}
|
||||||
|
142
i18n/locales/ar/data.json
Normal file
142
i18n/locales/ar/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/fa/data.json
Normal file
142
i18n/locales/fa/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/fi/data.json
Normal file
142
i18n/locales/fi/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/he/data.json
Normal file
142
i18n/locales/he/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/kk/data.json
Normal file
142
i18n/locales/kk/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/nl/data.json
Normal file
142
i18n/locales/nl/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/pl/data.json
Normal file
142
i18n/locales/pl/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/sv/data.json
Normal file
142
i18n/locales/sv/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
142
i18n/locales/uk/data.json
Normal file
142
i18n/locales/uk/data.json
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"Failed to add user": "Failed to add user",
|
||||||
|
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||||
|
"Please sign out first": "Please sign out first",
|
||||||
|
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"Challenge method should be S256": "Challenge method should be S256",
|
||||||
|
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||||
|
"Failed to login in: %s": "Failed to login in: %s",
|
||||||
|
"Invalid token": "Invalid token",
|
||||||
|
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||||
|
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||||
|
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||||
|
"The application: %s does not exist": "The application: %s does not exist",
|
||||||
|
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||||
|
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||||
|
"Unauthorized operation": "Unauthorized operation",
|
||||||
|
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||||
|
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
|
||||||
|
},
|
||||||
|
"cas": {
|
||||||
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
|
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||||
|
"Email already exists": "Email already exists",
|
||||||
|
"Email cannot be empty": "Email cannot be empty",
|
||||||
|
"Email is invalid": "Email is invalid",
|
||||||
|
"Empty username.": "Empty username.",
|
||||||
|
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||||
|
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||||
|
"LastName cannot be blank": "LastName cannot be blank",
|
||||||
|
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||||
|
"Organization does not exist": "Organization does not exist",
|
||||||
|
"Password must have at least 6 characters": "Password must have at least 6 characters",
|
||||||
|
"Phone already exists": "Phone already exists",
|
||||||
|
"Phone cannot be empty": "Phone cannot be empty",
|
||||||
|
"Phone number is invalid": "Phone number is invalid",
|
||||||
|
"Session outdated, please login again": "Session outdated, please login again",
|
||||||
|
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||||
|
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||||
|
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||||
|
"Username already exists": "Username already exists",
|
||||||
|
"Username cannot be an email address": "Username cannot be an email address",
|
||||||
|
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||||
|
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||||
|
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||||
|
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||||
|
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||||
|
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||||
|
"password or code is incorrect": "password or code is incorrect",
|
||||||
|
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||||
|
"unsupported password type: %s": "unsupported password type: %s"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"Missing parameter": "Missing parameter",
|
||||||
|
"Please login first": "Please login first",
|
||||||
|
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||||
|
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||||
|
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"Ldap server exist": "Ldap server exist"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"Please link first": "Please link first",
|
||||||
|
"This application has no providers": "This application has no providers",
|
||||||
|
"This application has no providers of type": "This application has no providers of type",
|
||||||
|
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||||
|
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||||
|
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||||
|
},
|
||||||
|
"organization": {
|
||||||
|
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||||
|
"The %s is immutable.": "The %s is immutable.",
|
||||||
|
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"Invalid application id": "Invalid application id",
|
||||||
|
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||||
|
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||||
|
},
|
||||||
|
"saml": {
|
||||||
|
"Application %s not found": "Application %s not found"
|
||||||
|
},
|
||||||
|
"saml_sp": {
|
||||||
|
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||||
|
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||||
|
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||||
|
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||||
|
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||||
|
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||||
|
"Invalid client_id": "Invalid client_id",
|
||||||
|
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||||
|
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"Display name cannot be empty": "Display name cannot be empty",
|
||||||
|
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||||
|
},
|
||||||
|
"user_upload": {
|
||||||
|
"Failed to import users": "Failed to import users"
|
||||||
|
},
|
||||||
|
"util": {
|
||||||
|
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||||
|
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"Code has not been sent yet!": "Code has not been sent yet!",
|
||||||
|
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||||
|
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||||
|
"Turing test failed.": "Turing test failed.",
|
||||||
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
|
"Unknown type": "Unknown type",
|
||||||
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
},
|
||||||
|
"webauthn": {
|
||||||
|
"Found no credentials for this user": "Found no credentials for this user",
|
||||||
|
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||||
|
}
|
||||||
|
}
|
@@ -72,13 +72,13 @@ type FacebookCheckToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FacebookCheckTokenData
|
// FacebookCheckTokenData
|
||||||
// Get more detail via: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken
|
// Get more detail via: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow#checktoken
|
||||||
type FacebookCheckTokenData struct {
|
type FacebookCheckTokenData struct {
|
||||||
UserId string `json:"user_id"`
|
UserId string `json:"user_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||||
// get more detail via: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#confirm
|
// get more detail via: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow#confirm
|
||||||
func (idp *FacebookIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
func (idp *FacebookIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Add("client_id", idp.Config.ClientID)
|
params.Add("client_id", idp.Config.ClientID)
|
||||||
|
@@ -24,20 +24,10 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Web3AuthTokenKey = "web3AuthToken"
|
|
||||||
|
|
||||||
type MetaMaskIdProvider struct {
|
type MetaMaskIdProvider struct {
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
type Web3AuthToken struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
Nonce string `json:"nonce"`
|
|
||||||
CreateAt uint64 `json:"createAt"`
|
|
||||||
TypedData string `json:"typedData"`
|
|
||||||
Signature string `json:"signature"` // signature for typed data
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMetaMaskIdProvider() *MetaMaskIdProvider {
|
func NewMetaMaskIdProvider() *MetaMaskIdProvider {
|
||||||
idp := &MetaMaskIdProvider{}
|
idp := &MetaMaskIdProvider{}
|
||||||
return idp
|
return idp
|
||||||
|
@@ -111,6 +111,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
|
|||||||
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
||||||
case "MetaMask":
|
case "MetaMask":
|
||||||
return NewMetaMaskIdProvider()
|
return NewMetaMaskIdProvider()
|
||||||
|
case "Web3Onboard":
|
||||||
|
return NewWeb3OnboardIdProvider()
|
||||||
default:
|
default:
|
||||||
if isGothSupport(idpInfo.Type) {
|
if isGothSupport(idpInfo.Type) {
|
||||||
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
|
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
|
||||||
|
103
idp/web3onboard.go
Normal file
103
idp/web3onboard.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package idp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Web3AuthTokenKey = "web3AuthToken"
|
||||||
|
|
||||||
|
type Web3AuthToken struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
CreateAt uint64 `json:"createAt"`
|
||||||
|
TypedData string `json:"typedData"` // typed data use for application
|
||||||
|
Signature string `json:"signature"` // signature for typed data
|
||||||
|
WalletType string `json:"walletType"` // e.g."MetaMask", "Coinbase"
|
||||||
|
}
|
||||||
|
|
||||||
|
type Web3OnboardIdProvider struct {
|
||||||
|
Client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWeb3OnboardIdProvider() *Web3OnboardIdProvider {
|
||||||
|
idp := &Web3OnboardIdProvider{}
|
||||||
|
return idp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *Web3OnboardIdProvider) SetHttpClient(client *http.Client) {
|
||||||
|
idp.Client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *Web3OnboardIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||||
|
web3AuthToken := Web3AuthToken{}
|
||||||
|
if err := json.Unmarshal([]byte(code), &web3AuthToken); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: fmt.Sprintf("%v:%v", Web3AuthTokenKey, web3AuthToken.Address),
|
||||||
|
TokenType: "Bearer",
|
||||||
|
Expiry: time.Now().AddDate(0, 1, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
token = token.WithExtra(map[string]interface{}{
|
||||||
|
Web3AuthTokenKey: web3AuthToken,
|
||||||
|
})
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *Web3OnboardIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||||
|
web3AuthToken, ok := token.Extra(Web3AuthTokenKey).(Web3AuthToken)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid web3AuthToken")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmtAddress := fmt.Sprintf("%v_%v",
|
||||||
|
strings.ReplaceAll(strings.TrimSpace(web3AuthToken.WalletType), " ", "_"),
|
||||||
|
web3AuthToken.Address,
|
||||||
|
)
|
||||||
|
userInfo := &UserInfo{
|
||||||
|
Id: fmtAddress,
|
||||||
|
Username: fmtAddress,
|
||||||
|
DisplayName: fmtAddress,
|
||||||
|
AvatarUrl: fmt.Sprintf("metamask:%v", forceEthereumAddress(web3AuthToken.Address)),
|
||||||
|
}
|
||||||
|
return userInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func forceEthereumAddress(address string) string {
|
||||||
|
// The required address to general MetaMask avatar is a string of length 42 that represents an Ethereum address.
|
||||||
|
// This function is used to force any address as an Ethereum address
|
||||||
|
address = strings.TrimSpace(address)
|
||||||
|
var builder strings.Builder
|
||||||
|
for _, ch := range address {
|
||||||
|
builder.WriteRune(ch)
|
||||||
|
}
|
||||||
|
for len(builder.String()) < 42 {
|
||||||
|
builder.WriteString("0")
|
||||||
|
}
|
||||||
|
if len(builder.String()) > 42 {
|
||||||
|
return builder.String()[:42]
|
||||||
|
}
|
||||||
|
return builder.String()
|
||||||
|
}
|
@@ -9,11 +9,11 @@
|
|||||||
"passwordType": "plain",
|
"passwordType": "plain",
|
||||||
"passwordSalt": "",
|
"passwordSalt": "",
|
||||||
"passwordOptions": ["AtLeast6"],
|
"passwordOptions": ["AtLeast6"],
|
||||||
"countryCodes": ["US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR"],
|
"countryCodes": ["US", "GB", "ES", "FR", "DE", "CN", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR", "DZ", "IL", "PH", "NL", "PL", "FI", "SE", "UA", "KZ"],
|
||||||
"defaultAvatar": "",
|
"defaultAvatar": "",
|
||||||
"defaultApplication": "",
|
"defaultApplication": "",
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr"],
|
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr","ar", "he", "nl", "pl", "fi", "sv", "uk", "kk", "fa"],
|
||||||
"masterPassword": "",
|
"masterPassword": "",
|
||||||
"initScore": 2000,
|
"initScore": 2000,
|
||||||
"enableSoftDeletion": false,
|
"enableSoftDeletion": false,
|
||||||
@@ -123,7 +123,6 @@
|
|||||||
"score": 2000,
|
"score": 2000,
|
||||||
"ranking": 1,
|
"ranking": 1,
|
||||||
"isAdmin": true,
|
"isAdmin": true,
|
||||||
"isGlobalAdmin": true,
|
|
||||||
"isForbidden": false,
|
"isForbidden": false,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"signupApplication": "",
|
"signupApplication": "",
|
||||||
|
@@ -62,7 +62,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if bindOrg == "built-in" || bindUser.IsGlobalAdmin {
|
if bindOrg == "built-in" || bindUser.IsGlobalAdmin() {
|
||||||
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
|
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
|
||||||
} else if bindUser.IsAdmin {
|
} else if bindUser.IsAdmin {
|
||||||
m.Client.IsOrgAdmin = true
|
m.Client.IsOrgAdmin = true
|
||||||
|
16
main.go
16
main.go
@@ -15,7 +15,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/beego/beego"
|
"github.com/beego/beego"
|
||||||
@@ -30,17 +29,10 @@ import (
|
|||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getCreateDatabaseFlag() bool {
|
|
||||||
res := flag.Bool("createDatabase", false, "true if you need Casdoor to create database")
|
|
||||||
flag.Parse()
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
createDatabase := getCreateDatabaseFlag()
|
object.InitFlag()
|
||||||
|
object.InitAdapter()
|
||||||
object.InitAdapter(createDatabase)
|
object.CreateTables()
|
||||||
object.CreateTables(createDatabase)
|
|
||||||
object.DoMigration()
|
object.DoMigration()
|
||||||
|
|
||||||
object.InitDb()
|
object.InitDb()
|
||||||
@@ -49,6 +41,8 @@ func main() {
|
|||||||
object.InitLdapAutoSynchronizer()
|
object.InitLdapAutoSynchronizer()
|
||||||
proxy.InitHttpClient()
|
proxy.InitHttpClient()
|
||||||
authz.InitApi()
|
authz.InitApi()
|
||||||
|
object.InitUserManager()
|
||||||
|
object.InitCasvisorConfig()
|
||||||
|
|
||||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||||
|
|
||||||
|
73
notification/custom_http.go
Normal file
73
notification/custom_http.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// 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 notification
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HttpNotificationClient struct {
|
||||||
|
endpoint string
|
||||||
|
method string
|
||||||
|
paramName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCustomHttpProvider(endpoint string, method string, paramName string) (*HttpNotificationClient, error) {
|
||||||
|
client := &HttpNotificationClient{
|
||||||
|
endpoint: endpoint,
|
||||||
|
method: method,
|
||||||
|
paramName: paramName,
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *HttpNotificationClient) Send(ctx context.Context, subject string, content string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
httpClient := proxy.DefaultHttpClient
|
||||||
|
|
||||||
|
req, err := http.NewRequest(c.method, c.endpoint, bytes.NewBufferString(content))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.method == "POST" {
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.PostForm = map[string][]string{
|
||||||
|
c.paramName: {content},
|
||||||
|
}
|
||||||
|
} else if c.method == "GET" {
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Add(c.paramName, content)
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("SendMessage() error, custom HTTP Notification request failed with status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -12,18 +12,16 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package util
|
package notification
|
||||||
|
|
||||||
import xormadapter "github.com/casdoor/xorm-adapter/v3"
|
import "github.com/nikoksr/notify"
|
||||||
|
|
||||||
func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
|
func GetNotificationProvider(typ string, appId string, receiver string, method string, title string) (notify.Notifier, error) {
|
||||||
s := []string{
|
if typ == "Telegram" {
|
||||||
casbinRule.V0,
|
return NewTelegramProvider(appId, receiver)
|
||||||
casbinRule.V1,
|
} else if typ == "Custom HTTP" {
|
||||||
casbinRule.V2,
|
return NewCustomHttpProvider(receiver, method, title)
|
||||||
casbinRule.V3,
|
|
||||||
casbinRule.V4,
|
|
||||||
casbinRule.V5,
|
|
||||||
}
|
}
|
||||||
return s
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
42
notification/telegram.go
Normal file
42
notification/telegram.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// 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 notification
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/proxy"
|
||||||
|
api "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
|
"github.com/nikoksr/notify"
|
||||||
|
"github.com/nikoksr/notify/service/telegram"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTelegramProvider(apiToken string, chatIdStr string) (notify.Notifier, error) {
|
||||||
|
client, err := api.NewBotAPIWithClient(apiToken, proxy.ProxyHttpClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
t := &telegram.Telegram{}
|
||||||
|
t.SetClient(client)
|
||||||
|
|
||||||
|
chatId, err := strconv.ParseInt(chatIdStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.AddReceivers(chatId)
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
@@ -18,11 +18,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/casbin/casbin/v2/model"
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
|
"github.com/xorm-io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Adapter struct {
|
type Adapter struct {
|
||||||
@@ -40,8 +40,6 @@ type Adapter struct {
|
|||||||
Table string `xorm:"varchar(100)" json:"table"`
|
Table string `xorm:"varchar(100)" json:"table"`
|
||||||
TableNamePrefix string `xorm:"varchar(100)" json:"tableNamePrefix"`
|
TableNamePrefix string `xorm:"varchar(100)" json:"tableNamePrefix"`
|
||||||
|
|
||||||
IsEnabled bool `json:"isEnabled"`
|
|
||||||
|
|
||||||
*xormadapter.Adapter `xorm:"-" json:"-"`
|
*xormadapter.Adapter `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,20 +147,23 @@ func (adapter *Adapter) getTable() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Adapter) initAdapter() error {
|
func (adapter *Adapter) InitAdapter() error {
|
||||||
if adapter.Adapter == nil {
|
if adapter.Adapter == nil {
|
||||||
var dataSourceName string
|
var dataSourceName string
|
||||||
|
|
||||||
if adapter.builtInAdapter() {
|
if adapter.isBuiltIn() {
|
||||||
dataSourceName = conf.GetConfigString("dataSourceName")
|
dataSourceName = conf.GetConfigString("dataSourceName")
|
||||||
|
if adapter.DatabaseType == "mysql" {
|
||||||
|
dataSourceName = dataSourceName + adapter.Database
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch adapter.DatabaseType {
|
switch adapter.DatabaseType {
|
||||||
case "mssql":
|
case "mssql":
|
||||||
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", adapter.User,
|
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "mysql":
|
case "mysql":
|
||||||
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", adapter.User,
|
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
case "postgres":
|
case "postgres":
|
||||||
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", adapter.User,
|
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", adapter.User,
|
||||||
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
adapter.Password, adapter.Host, adapter.Port, adapter.Database)
|
||||||
@@ -181,7 +182,16 @@ func (adapter *Adapter) initAdapter() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(adapter.DatabaseType, dataSourceName, adapter.Database).Engine, adapter.getTable(), adapter.TableNamePrefix)
|
engine, err := xorm.NewEngine(adapter.DatabaseType, dataSourceName)
|
||||||
|
|
||||||
|
if adapter.isBuiltIn() && adapter.DatabaseType == "postgres" {
|
||||||
|
schema := util.GetValueFromDataSourceName("search_path", dataSourceName)
|
||||||
|
if schema != "" {
|
||||||
|
engine.SetSchema(schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(engine, adapter.getTable(), adapter.TableNamePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -209,116 +219,10 @@ func adapterChangeTrigger(oldName string, newName string) error {
|
|||||||
return session.Commit()
|
return session.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func safeReturn(policy []string, i int) string {
|
func (adapter *Adapter) isBuiltIn() bool {
|
||||||
if len(policy) > i {
|
|
||||||
return policy[i]
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func matrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
|
|
||||||
res := []*xormadapter.CasbinRule{}
|
|
||||||
|
|
||||||
for _, policy := range policies {
|
|
||||||
line := xormadapter.CasbinRule{
|
|
||||||
Ptype: Ptype,
|
|
||||||
V0: safeReturn(policy, 0),
|
|
||||||
V1: safeReturn(policy, 1),
|
|
||||||
V2: safeReturn(policy, 2),
|
|
||||||
V3: safeReturn(policy, 3),
|
|
||||||
V4: safeReturn(policy, 4),
|
|
||||||
V5: safeReturn(policy, 5),
|
|
||||||
}
|
|
||||||
res = append(res, &line)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPolicies(adapter *Adapter) ([]*xormadapter.CasbinRule, error) {
|
|
||||||
err := adapter.initAdapter()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinModel := getModelDef()
|
|
||||||
err = adapter.LoadPolicy(casbinModel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
policies := matrixToCasbinRules("p", casbinModel.GetPolicy("p", "p"))
|
|
||||||
policies = append(policies, matrixToCasbinRules("g", casbinModel.GetPolicy("g", "g"))...)
|
|
||||||
return policies, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdatePolicy(oldPolicy, newPolicy []string, adapter *Adapter) (bool, error) {
|
|
||||||
err := adapter.initAdapter()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinModel := getModelDef()
|
|
||||||
err = adapter.LoadPolicy(casbinModel)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
affected := casbinModel.UpdatePolicy("p", "p", oldPolicy, newPolicy)
|
|
||||||
if err != nil {
|
|
||||||
return affected, err
|
|
||||||
}
|
|
||||||
return affected, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddPolicy(policy []string, adapter *Adapter) (bool, error) {
|
|
||||||
err := adapter.initAdapter()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinModel := getModelDef()
|
|
||||||
err = adapter.LoadPolicy(casbinModel)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinModel.AddPolicy("p", "p", policy)
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemovePolicy(policy []string, adapter *Adapter) (bool, error) {
|
|
||||||
err := adapter.initAdapter()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinModel := getModelDef()
|
|
||||||
err = adapter.LoadPolicy(casbinModel)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
affected := casbinModel.RemovePolicy("p", "p", policy)
|
|
||||||
if err != nil {
|
|
||||||
return affected, err
|
|
||||||
}
|
|
||||||
return affected, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (adapter *Adapter) builtInAdapter() bool {
|
|
||||||
if adapter.Owner != "built-in" {
|
if adapter.Owner != "built-in" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapter.Name == "permission-adapter-built-in" || adapter.Name == "api-adapter-built-in"
|
return adapter.Name == "user-adapter-built-in" || adapter.Name == "api-adapter-built-in"
|
||||||
}
|
|
||||||
|
|
||||||
func getModelDef() model.Model {
|
|
||||||
casbinModel := model.NewModel()
|
|
||||||
casbinModel.AddDef("p", "p", "_, _, _, _, _, _")
|
|
||||||
casbinModel.AddDef("g", "g", "_, _, _, _, _, _")
|
|
||||||
return casbinModel
|
|
||||||
}
|
}
|
||||||
|
@@ -57,7 +57,9 @@ type Application struct {
|
|||||||
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
|
SignupItems []*SignupItem `xorm:"varchar(1000)" 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"`
|
||||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||||
|
InvitationCodes []string `xorm:"varchar(200)" json:"invitationCodes"`
|
||||||
|
|
||||||
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"`
|
||||||
@@ -311,6 +313,11 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
|||||||
application.OrganizationObj.PasswordSalt = "***"
|
application.OrganizationObj.PasswordSalt = "***"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if application.InvitationCodes != nil {
|
||||||
|
application.InvitationCodes = []string{"***"}
|
||||||
|
}
|
||||||
|
|
||||||
return application
|
return application
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -66,8 +66,11 @@ func CheckUserSignup(application *Application, organization *Organization, form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(form.Password) <= 5 {
|
if application.IsSignupItemVisible("Password") {
|
||||||
return i18n.Translate(lang, "check:Password must have at least 6 characters")
|
msg := CheckPasswordComplexityByOrg(organization, form.Password)
|
||||||
|
if msg != "" {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Email") {
|
if application.IsSignupItemVisible("Email") {
|
||||||
@@ -124,6 +127,18 @@ func CheckUserSignup(application *Application, organization *Organization, form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(application.InvitationCodes) > 0 {
|
||||||
|
if form.InvitationCode == "" {
|
||||||
|
if application.IsSignupItemRequired("Invitation code") {
|
||||||
|
return i18n.Translate(lang, "check:Invitation code cannot be blank")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !util.InSlice(application.InvitationCodes, form.InvitationCode) {
|
||||||
|
return i18n.Translate(lang, "check:Invitation code is invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +156,7 @@ func checkSigninErrorTimes(user *User, lang string) string {
|
|||||||
// reset the error times
|
// reset the error times
|
||||||
user.SigninWrongTimes = 0
|
user.SigninWrongTimes = 0
|
||||||
|
|
||||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, user.IsGlobalAdmin)
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
@@ -319,7 +334,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
|||||||
if requestUser == nil {
|
if requestUser == nil {
|
||||||
return false, fmt.Errorf(i18n.Translate(lang, "check:Session outdated, please login again"))
|
return false, fmt.Errorf(i18n.Translate(lang, "check:Session outdated, please login again"))
|
||||||
}
|
}
|
||||||
if requestUser.IsGlobalAdmin {
|
if requestUser.IsGlobalAdmin() {
|
||||||
hasPermission = true
|
hasPermission = true
|
||||||
} else if requestUserId == userId {
|
} else if requestUserId == userId {
|
||||||
hasPermission = true
|
hasPermission = true
|
||||||
@@ -391,10 +406,6 @@ func CheckUsername(username string, lang string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CheckUpdateUser(oldUser, user *User, lang string) string {
|
func CheckUpdateUser(oldUser, user *User, lang string) string {
|
||||||
if user.DisplayName == "" {
|
|
||||||
return i18n.Translate(lang, "user:Display name cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldUser.Name != user.Name {
|
if oldUser.Name != user.Name {
|
||||||
if msg := CheckUsername(user.Name, lang); msg != "" {
|
if msg := CheckUsername(user.Name, lang); msg != "" {
|
||||||
return msg
|
return msg
|
||||||
@@ -404,7 +415,7 @@ func CheckUpdateUser(oldUser, user *User, lang string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if oldUser.Email != user.Email {
|
if oldUser.Email != user.Email {
|
||||||
if HasUserByField(user.Name, "email", user.Email) {
|
if HasUserByField(user.Owner, "email", user.Email) {
|
||||||
return i18n.Translate(lang, "check:Email already exists")
|
return i18n.Translate(lang, "check:Email already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,7 +42,7 @@ func resetUserSigninErrorTimes(user *User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.SigninWrongTimes = 0
|
user.SigninWrongTimes = 0
|
||||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func recordSigninErrorInfo(user *User, lang string, options ...bool) string {
|
func recordSigninErrorInfo(user *User, lang string, options ...bool) string {
|
||||||
@@ -61,7 +61,7 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update user
|
// update user
|
||||||
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
|
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, false)
|
||||||
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
|
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
|
||||||
if leftChances == 0 && enableCaptcha {
|
if leftChances == 0 && enableCaptcha {
|
||||||
return fmt.Sprint(i18n.Translate(lang, "check:password or code is incorrect"))
|
return fmt.Sprint(i18n.Translate(lang, "check:password or code is incorrect"))
|
||||||
|
@@ -15,10 +15,12 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
|
|
||||||
"github.com/casbin/casbin/v2"
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/casbin/casbin/v2/config"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
|
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,10 +32,10 @@ type Enforcer struct {
|
|||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
Model string `xorm:"varchar(100)" json:"model"`
|
Model string `xorm:"varchar(100)" json:"model"`
|
||||||
Adapter string `xorm:"varchar(100)" json:"adapter"`
|
Adapter string `xorm:"varchar(100)" json:"adapter"`
|
||||||
IsEnabled bool `json:"isEnabled"`
|
|
||||||
|
|
||||||
|
ModelCfg map[string]string `xorm:"-" json:"modelCfg"`
|
||||||
*casbin.Enforcer
|
*casbin.Enforcer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,44 +122,131 @@ func DeleteEnforcer(enforcer *Enforcer) (bool, error) {
|
|||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (enforcer *Enforcer) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", enforcer.Owner, enforcer.Name)
|
||||||
|
}
|
||||||
|
|
||||||
func (enforcer *Enforcer) InitEnforcer() error {
|
func (enforcer *Enforcer) InitEnforcer() error {
|
||||||
if enforcer.Enforcer == nil {
|
if enforcer.Enforcer != nil {
|
||||||
if enforcer == nil {
|
return nil
|
||||||
return errors.New("enforcer is nil")
|
}
|
||||||
}
|
|
||||||
if enforcer.Model == "" || enforcer.Adapter == "" {
|
|
||||||
return errors.New("missing model or adapter")
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
if enforcer.Model == "" {
|
||||||
var m *Model
|
return fmt.Errorf("the model for enforcer: %s should not be empty", enforcer.GetId())
|
||||||
var a *Adapter
|
}
|
||||||
|
if enforcer.Adapter == "" {
|
||||||
|
return fmt.Errorf("the adapter for enforcer: %s should not be empty", enforcer.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
if m, err = GetModel(enforcer.Model); err != nil {
|
m, err := GetModel(enforcer.Model)
|
||||||
return err
|
if err != nil {
|
||||||
} else if m == nil {
|
return err
|
||||||
return errors.New("model not found")
|
} else if m == nil {
|
||||||
}
|
return fmt.Errorf("the model: %s for enforcer: %s is not found", enforcer.Model, enforcer.GetId())
|
||||||
if a, err = GetAdapter(enforcer.Adapter); err != nil {
|
}
|
||||||
return err
|
|
||||||
} else if a == nil {
|
|
||||||
return errors.New("adapter not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = m.initModel()
|
a, err := GetAdapter(enforcer.Adapter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
} else if a == nil {
|
||||||
err = a.initAdapter()
|
return fmt.Errorf("the adapter: %s for enforcer: %s is not found", enforcer.Adapter, enforcer.GetId())
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
casbinEnforcer, err := casbin.NewEnforcer(m.Model, a.Adapter)
|
err = m.initModel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
enforcer.Enforcer = casbinEnforcer
|
err = a.InitAdapter()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
casbinEnforcer, err := casbin.NewEnforcer(m.Model, a.Adapter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enforcer.Enforcer = casbinEnforcer
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInitializedEnforcer(enforcerId string) (*Enforcer, error) {
|
||||||
|
enforcer, err := GetEnforcer(enforcerId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if enforcer == nil {
|
||||||
|
return nil, fmt.Errorf("the enforcer: %s is not found", enforcerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = enforcer.InitEnforcer()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return enforcer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPolicies(id string) ([]*xormadapter.CasbinRule, error) {
|
||||||
|
enforcer, err := GetInitializedEnforcer(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
policies := util.MatrixToCasbinRules("p", enforcer.GetPolicy())
|
||||||
|
if enforcer.GetModel()["g"] != nil {
|
||||||
|
policies = append(policies, util.MatrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return policies, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePolicy(id string, oldPolicy, newPolicy []string) (bool, error) {
|
||||||
|
enforcer, err := GetInitializedEnforcer(id)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return enforcer.UpdatePolicy(oldPolicy, newPolicy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddPolicy(id string, policy []string) (bool, error) {
|
||||||
|
enforcer, err := GetInitializedEnforcer(id)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return enforcer.AddPolicy(policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemovePolicy(id string, policy []string) (bool, error) {
|
||||||
|
enforcer, err := GetInitializedEnforcer(id)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return enforcer.RemovePolicy(policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enforcer *Enforcer) LoadModelCfg() error {
|
||||||
|
if enforcer.ModelCfg != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
model, err := GetModel(enforcer.Model)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if model == nil {
|
||||||
|
return fmt.Errorf("the model: %s for enforcer: %s is not found", enforcer.Model, enforcer.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := config.NewConfigFromText(model.ModelText)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enforcer.ModelCfg = make(map[string]string)
|
||||||
|
enforcer.ModelCfg["p"] = cfg.String("policy_definition::p")
|
||||||
|
if cfg.String("role_definition::g") != "" {
|
||||||
|
enforcer.ModelCfg["g"] = cfg.String("role_definition::g")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
140
object/get-dashboard.go
Normal file
140
object/get-dashboard.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dashboard struct {
|
||||||
|
OrganizationCounts []int `json:"organizationCounts"`
|
||||||
|
UserCounts []int `json:"userCounts"`
|
||||||
|
ProviderCounts []int `json:"providerCounts"`
|
||||||
|
ApplicationCounts []int `json:"applicationCounts"`
|
||||||
|
SubscriptionCounts []int `json:"subscriptionCounts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDashboard(owner string) (*Dashboard, error) {
|
||||||
|
dashboard := &Dashboard{
|
||||||
|
OrganizationCounts: make([]int, 31),
|
||||||
|
UserCounts: make([]int, 31),
|
||||||
|
ProviderCounts: make([]int, 31),
|
||||||
|
ApplicationCounts: make([]int, 31),
|
||||||
|
SubscriptionCounts: make([]int, 31),
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
organizations := []Organization{}
|
||||||
|
users := []User{}
|
||||||
|
providers := []Provider{}
|
||||||
|
applications := []Application{}
|
||||||
|
subscriptions := []Subscription{}
|
||||||
|
|
||||||
|
wg.Add(5)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := ormer.Engine.Find(&organizations, &Organization{Owner: owner}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
if err := ormer.Engine.Find(&users, &User{Owner: owner}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
if err := ormer.Engine.Find(&providers, &Provider{Owner: owner}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
if err := ormer.Engine.Find(&applications, &Application{Owner: owner}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
if err := ormer.Engine.Find(&subscriptions, &Subscription{Owner: owner}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
nowTime := time.Now()
|
||||||
|
for i := 30; i >= 0; i-- {
|
||||||
|
cutTime := nowTime.AddDate(0, 0, -i)
|
||||||
|
dashboard.OrganizationCounts[30-i] = countCreatedBefore(organizations, cutTime)
|
||||||
|
dashboard.UserCounts[30-i] = countCreatedBefore(users, cutTime)
|
||||||
|
dashboard.ProviderCounts[30-i] = countCreatedBefore(providers, cutTime)
|
||||||
|
dashboard.ApplicationCounts[30-i] = countCreatedBefore(applications, cutTime)
|
||||||
|
dashboard.SubscriptionCounts[30-i] = countCreatedBefore(subscriptions, cutTime)
|
||||||
|
}
|
||||||
|
return dashboard, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func countCreatedBefore(objects interface{}, before time.Time) int {
|
||||||
|
count := 0
|
||||||
|
switch obj := objects.(type) {
|
||||||
|
case []Organization:
|
||||||
|
for _, o := range obj {
|
||||||
|
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", o.CreatedTime)
|
||||||
|
if createdTime.Before(before) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []User:
|
||||||
|
for _, u := range obj {
|
||||||
|
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", u.CreatedTime)
|
||||||
|
if createdTime.Before(before) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []Provider:
|
||||||
|
for _, p := range obj {
|
||||||
|
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", p.CreatedTime)
|
||||||
|
if createdTime.Before(before) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []Application:
|
||||||
|
for _, a := range obj {
|
||||||
|
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", a.CreatedTime)
|
||||||
|
if createdTime.Before(before) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []Subscription:
|
||||||
|
for _, s := range obj {
|
||||||
|
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", s.CreatedTime)
|
||||||
|
if createdTime.Before(before) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
@@ -214,30 +214,18 @@ func ConvertToTreeData(groups []*Group, parentId string) []*Group {
|
|||||||
return treeData
|
return treeData
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveUserFromGroup(owner, name, groupId string) (bool, error) {
|
|
||||||
user, err := getUser(owner, name)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if user == nil {
|
|
||||||
return false, errors.New("user not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
user.Groups = util.DeleteVal(user.Groups, groupId)
|
|
||||||
affected, err := updateUser(user.GetId(), user, []string{"groups"})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return affected != 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
||||||
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if field == "" && value == "" {
|
if field == "" && value == "" {
|
||||||
return ormer.Engine.Where(builder.Like{"`groups`", groupId}).
|
return int64(len(names)), nil
|
||||||
Count(&User{})
|
|
||||||
} else {
|
} else {
|
||||||
return ormer.Engine.Table("user").
|
return ormer.Engine.Table("user").
|
||||||
Where(builder.Like{"`groups`", groupId}).
|
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()
|
||||||
}
|
}
|
||||||
@@ -245,8 +233,14 @@ func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
|||||||
|
|
||||||
func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
|
func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
|
||||||
users := []*User{}
|
users := []*User{}
|
||||||
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
session := ormer.Engine.Table("user").
|
session := ormer.Engine.Table("user").
|
||||||
Where(builder.Like{"`groups`", groupId + "\""})
|
Where("owner = ?", owner).In("name", names)
|
||||||
|
|
||||||
if offset != -1 && limit != -1 {
|
if offset != -1 && limit != -1 {
|
||||||
session.Limit(limit, offset)
|
session.Limit(limit, offset)
|
||||||
@@ -265,7 +259,7 @@ func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, so
|
|||||||
session = session.Desc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
session = session.Desc(fmt.Sprintf("user.%s", util.SnakeString(sortField)))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := session.Find(&users)
|
err = session.Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -275,13 +269,13 @@ func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, so
|
|||||||
|
|
||||||
func GetGroupUsers(groupId string) ([]*User, error) {
|
func GetGroupUsers(groupId string) ([]*User, error) {
|
||||||
users := []*User{}
|
users := []*User{}
|
||||||
err := ormer.Engine.Table("user").
|
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||||
Where(builder.Like{"`groups`", groupId + "\""}).
|
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||||
Find(&users)
|
|
||||||
|
err = ormer.Engine.Where("owner = ?", owner).In("name", names).Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -73,7 +73,6 @@ func getBuiltInAccountItems() []*AccountItem {
|
|||||||
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
|
||||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
@@ -145,7 +144,6 @@ func initBuiltInUser() {
|
|||||||
Score: 2000,
|
Score: 2000,
|
||||||
Ranking: 1,
|
Ranking: 1,
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
IsGlobalAdmin: true,
|
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
IsDeleted: false,
|
IsDeleted: false,
|
||||||
SignupApplication: "app-built-in",
|
SignupApplication: "app-built-in",
|
||||||
@@ -318,7 +316,6 @@ func initBuiltInUserModel() {
|
|||||||
Name: "user-model-built-in",
|
Name: "user-model-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Built-in Model",
|
DisplayName: "Built-in Model",
|
||||||
IsEnabled: true,
|
|
||||||
ModelText: `[request_definition]
|
ModelText: `[request_definition]
|
||||||
r = sub, obj, act
|
r = sub, obj, act
|
||||||
|
|
||||||
@@ -376,7 +373,6 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
|
|||||||
Name: "api-model-built-in",
|
Name: "api-model-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "API Model",
|
DisplayName: "API Model",
|
||||||
IsEnabled: true,
|
|
||||||
ModelText: modelText,
|
ModelText: modelText,
|
||||||
}
|
}
|
||||||
_, err = AddModel(model)
|
_, err = AddModel(model)
|
||||||
@@ -435,7 +431,6 @@ func initBuiltInUserAdapter() {
|
|||||||
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
|
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
|
||||||
Database: conf.GetConfigString("dbName"),
|
Database: conf.GetConfigString("dbName"),
|
||||||
Table: "casbin_user_rule",
|
Table: "casbin_user_rule",
|
||||||
IsEnabled: true,
|
|
||||||
}
|
}
|
||||||
_, err = AddAdapter(adapter)
|
_, err = AddAdapter(adapter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -462,7 +457,6 @@ func initBuiltInApiAdapter() {
|
|||||||
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
|
TableNamePrefix: conf.GetConfigString("tableNamePrefix"),
|
||||||
Database: conf.GetConfigString("dbName"),
|
Database: conf.GetConfigString("dbName"),
|
||||||
Table: "casbin_api_rule",
|
Table: "casbin_api_rule",
|
||||||
IsEnabled: true,
|
|
||||||
}
|
}
|
||||||
_, err = AddAdapter(adapter)
|
_, err = AddAdapter(adapter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -484,10 +478,9 @@ func initBuiltInUserEnforcer() {
|
|||||||
Owner: "built-in",
|
Owner: "built-in",
|
||||||
Name: "user-enforcer-built-in",
|
Name: "user-enforcer-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Permission Enforcer",
|
DisplayName: "User Enforcer",
|
||||||
Model: "built-in/user-model-built-in",
|
Model: "built-in/user-model-built-in",
|
||||||
Adapter: "built-in/user-adapter-built-in",
|
Adapter: "built-in/user-adapter-built-in",
|
||||||
IsEnabled: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = AddEnforcer(enforcer)
|
_, err = AddEnforcer(enforcer)
|
||||||
@@ -513,7 +506,6 @@ func initBuiltInApiEnforcer() {
|
|||||||
DisplayName: "API Enforcer",
|
DisplayName: "API Enforcer",
|
||||||
Model: "built-in/api-model-built-in",
|
Model: "built-in/api-model-built-in",
|
||||||
Adapter: "built-in/api-adapter-built-in",
|
Adapter: "built-in/api-adapter-built-in",
|
||||||
IsEnabled: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = AddEnforcer(enforcer)
|
_, err = AddEnforcer(enforcer)
|
||||||
|
@@ -41,19 +41,20 @@ type LdapUser struct {
|
|||||||
GidNumber string `json:"gidNumber"`
|
GidNumber string `json:"gidNumber"`
|
||||||
// Gcn string
|
// Gcn string
|
||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
|
UserPrincipalName string `json:"userPrincipalName"`
|
||||||
DisplayName string `json:"displayName"`
|
DisplayName string `json:"displayName"`
|
||||||
Mail string
|
Mail string
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
EmailAddress string
|
EmailAddress string
|
||||||
TelephoneNumber string
|
TelephoneNumber string
|
||||||
Mobile string
|
Mobile string `json:"mobile"`
|
||||||
MobileTelephoneNumber string
|
MobileTelephoneNumber string
|
||||||
RegisteredAddress string
|
RegisteredAddress string
|
||||||
PostalAddress string
|
PostalAddress string
|
||||||
|
|
||||||
GroupId string `json:"groupId"`
|
GroupId string `json:"groupId"`
|
||||||
Phone string `json:"phone"`
|
Address string `json:"address"`
|
||||||
Address string `json:"address"`
|
MemberOf string `json:"memberOf"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
||||||
@@ -168,6 +169,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
|||||||
user.Uuid = attribute.Values[0]
|
user.Uuid = attribute.Values[0]
|
||||||
case "objectGUID":
|
case "objectGUID":
|
||||||
user.Uuid = attribute.Values[0]
|
user.Uuid = attribute.Values[0]
|
||||||
|
case "userPrincipalName":
|
||||||
|
user.UserPrincipalName = attribute.Values[0]
|
||||||
case "displayName":
|
case "displayName":
|
||||||
user.DisplayName = attribute.Values[0]
|
user.DisplayName = attribute.Values[0]
|
||||||
case "mail":
|
case "mail":
|
||||||
@@ -186,6 +189,8 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
|||||||
user.RegisteredAddress = attribute.Values[0]
|
user.RegisteredAddress = attribute.Values[0]
|
||||||
case "postalAddress":
|
case "postalAddress":
|
||||||
user.PostalAddress = attribute.Values[0]
|
user.PostalAddress = attribute.Values[0]
|
||||||
|
case "memberOf":
|
||||||
|
user.MemberOf = attribute.Values[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ldapUsers = append(ldapUsers, user)
|
ldapUsers = append(ldapUsers, user)
|
||||||
@@ -306,18 +311,20 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
|
|||||||
}
|
}
|
||||||
|
|
||||||
newUser := &User{
|
newUser := &User{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Name: name,
|
Name: name,
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: syncUser.buildLdapDisplayName(),
|
DisplayName: syncUser.buildLdapDisplayName(),
|
||||||
Avatar: organization.DefaultAvatar,
|
SignupApplication: organization.DefaultApplication,
|
||||||
Email: syncUser.Email,
|
Type: "normal-user",
|
||||||
Phone: syncUser.Phone,
|
Avatar: organization.DefaultAvatar,
|
||||||
Address: []string{syncUser.Address},
|
Email: syncUser.Email,
|
||||||
Affiliation: affiliation,
|
Phone: syncUser.Mobile,
|
||||||
Tag: tag,
|
Address: []string{syncUser.Address},
|
||||||
Score: score,
|
Affiliation: affiliation,
|
||||||
Ldap: syncUser.Uuid,
|
Tag: tag,
|
||||||
|
Score: score,
|
||||||
|
Ldap: syncUser.Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := AddUser(newUser)
|
affected, err := AddUser(newUser)
|
||||||
|
@@ -84,7 +84,7 @@ func MfaRecover(user *User, recoveryCode string) error {
|
|||||||
return fmt.Errorf("recovery code not found")
|
return fmt.Errorf("recovery code not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := UpdateUser(user.GetId(), user, []string{"recovery_codes"}, user.IsAdminUser())
|
_, err := UpdateUser(user.GetId(), user, []string{"recovery_codes"}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ func DisabledMultiFactorAuth(user *User) error {
|
|||||||
func SetPreferredMultiFactorAuth(user *User, mfaType string) error {
|
func SetPreferredMultiFactorAuth(user *User, mfaType string) error {
|
||||||
user.PreferredMfaType = mfaType
|
user.PreferredMfaType = mfaType
|
||||||
|
|
||||||
_, err := UpdateUser(user.GetId(), user, []string{"preferred_mfa_type"}, user.IsAdminUser())
|
_, err := UpdateUser(user.GetId(), user, []string{"preferred_mfa_type"}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package object
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/beego/beego"
|
"github.com/beego/beego"
|
||||||
"github.com/beego/beego/context"
|
"github.com/beego/beego/context"
|
||||||
@@ -25,7 +26,10 @@ import (
|
|||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MfaTotpSecretSession = "mfa_totp_secret"
|
const (
|
||||||
|
MfaTotpSecretSession = "mfa_totp_secret"
|
||||||
|
MfaTotpPeriodInSeconds = 30
|
||||||
|
)
|
||||||
|
|
||||||
type TotpMfa struct {
|
type TotpMfa struct {
|
||||||
Config *MfaProps
|
Config *MfaProps
|
||||||
@@ -76,7 +80,16 @@ func (mfa *TotpMfa) SetupVerify(ctx *context.Context, passcode string) error {
|
|||||||
if secret == nil {
|
if secret == nil {
|
||||||
return errors.New("totp secret is missing")
|
return errors.New("totp secret is missing")
|
||||||
}
|
}
|
||||||
result := totp.Validate(passcode, secret.(string))
|
|
||||||
|
result, err := totp.ValidateCustom(passcode, secret.(string), time.Now().UTC(), totp.ValidateOpts{
|
||||||
|
Period: MfaTotpPeriodInSeconds,
|
||||||
|
Skew: 1,
|
||||||
|
Digits: otp.DigitsSix,
|
||||||
|
Algorithm: otp.AlgorithmSHA1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
return nil
|
return nil
|
||||||
@@ -115,7 +128,15 @@ func (mfa *TotpMfa) Enable(ctx *context.Context, user *User) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mfa *TotpMfa) Verify(passcode string) error {
|
func (mfa *TotpMfa) Verify(passcode string) error {
|
||||||
result := totp.Validate(passcode, mfa.Config.Secret)
|
result, err := totp.ValidateCustom(passcode, mfa.Config.Secret, time.Now().UTC(), totp.ValidateOpts{
|
||||||
|
Period: MfaTotpPeriodInSeconds,
|
||||||
|
Skew: 1,
|
||||||
|
Digits: otp.DigitsSix,
|
||||||
|
Algorithm: otp.AlgorithmSHA1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
return nil
|
return nil
|
||||||
@@ -133,7 +154,7 @@ func NewTotpMfaUtil(config *MfaProps) *TotpMfa {
|
|||||||
|
|
||||||
return &TotpMfa{
|
return &TotpMfa{
|
||||||
Config: config,
|
Config: config,
|
||||||
period: 30,
|
period: MfaTotpPeriodInSeconds,
|
||||||
secretSize: 20,
|
secretSize: 20,
|
||||||
digits: otp.DigitsSix,
|
digits: otp.DigitsSix,
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,6 @@ type Model struct {
|
|||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
ModelText string `xorm:"mediumtext" json:"modelText"`
|
ModelText string `xorm:"mediumtext" json:"modelText"`
|
||||||
IsEnabled bool `json:"isEnabled"`
|
|
||||||
|
|
||||||
model.Model `xorm:"-" json:"-"`
|
model.Model `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
42
object/notification.go
Normal file
42
object/notification.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// 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 (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/notification"
|
||||||
|
"github.com/nikoksr/notify"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNotificationClient(provider *Provider) (notify.Notifier, error) {
|
||||||
|
var client notify.Notifier
|
||||||
|
client, err := notification.GetNotificationProvider(provider.Type, provider.AppId, provider.Receiver, provider.Method, provider.Title)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendNotification(provider *Provider, content string) error {
|
||||||
|
client, err := getNotificationClient(provider)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.Send(context.Background(), "", content)
|
||||||
|
return err
|
||||||
|
}
|
@@ -103,7 +103,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
|||||||
SubjectTypesSupported: []string{"public"},
|
SubjectTypesSupported: []string{"public"},
|
||||||
IdTokenSigningAlgValuesSupported: []string{"RS256"},
|
IdTokenSigningAlgValuesSupported: []string{"RS256"},
|
||||||
ScopesSupported: []string{"openid", "email", "profile", "address", "phone", "offline_access"},
|
ScopesSupported: []string{"openid", "email", "profile", "address", "phone", "offline_access"},
|
||||||
ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isGlobalAdmin", "isForbidden", "signupApplication", "ldap"},
|
ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isForbidden", "signupApplication", "ldap"},
|
||||||
RequestParameterSupported: true,
|
RequestParameterSupported: true,
|
||||||
RequestObjectSigningAlgValuesSupported: []string{"HS256", "HS384", "HS512"},
|
RequestObjectSigningAlgValuesSupported: []string{"HS256", "HS384", "HS512"},
|
||||||
EndSessionEndpoint: fmt.Sprintf("%s/api/logout", originBackend),
|
EndSessionEndpoint: fmt.Sprintf("%s/api/logout", originBackend),
|
||||||
|
@@ -437,14 +437,6 @@ func organizationChangeTrigger(oldName string, newName string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
record := new(Record)
|
|
||||||
record.Owner = newName
|
|
||||||
record.Organization = newName
|
|
||||||
_, err = session.Where("organization=?", oldName).Update(record)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resource := new(Resource)
|
resource := new(Resource)
|
||||||
resource.Owner = newName
|
resource.Owner = newName
|
||||||
_, err = session.Where("owner=?", oldName).Update(resource)
|
_, err = session.Where("owner=?", oldName).Update(resource)
|
||||||
|
147
object/ormer.go
147
object/ormer.go
@@ -16,7 +16,10 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -32,7 +35,24 @@ import (
|
|||||||
_ "modernc.org/sqlite" // db = sqlite
|
_ "modernc.org/sqlite" // db = sqlite
|
||||||
)
|
)
|
||||||
|
|
||||||
var ormer *Ormer
|
var (
|
||||||
|
ormer *Ormer = nil
|
||||||
|
isCreateDatabaseDefined = false
|
||||||
|
createDatabase = true
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitFlag() {
|
||||||
|
if !isCreateDatabaseDefined {
|
||||||
|
isCreateDatabaseDefined = true
|
||||||
|
createDatabase = getCreateDatabaseFlag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCreateDatabaseFlag() bool {
|
||||||
|
res := flag.Bool("createDatabase", false, "true if you need to create database")
|
||||||
|
flag.Parse()
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
func InitConfig() {
|
func InitConfig() {
|
||||||
err := beego.LoadAppConfig("ini", "../conf/app.conf")
|
err := beego.LoadAppConfig("ini", "../conf/app.conf")
|
||||||
@@ -42,12 +62,23 @@ func InitConfig() {
|
|||||||
|
|
||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
|
|
||||||
InitAdapter(true)
|
InitAdapter()
|
||||||
CreateTables(true)
|
CreateTables()
|
||||||
DoMigration()
|
DoMigration()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitAdapter(createDatabase bool) {
|
func InitAdapter() {
|
||||||
|
if conf.GetConfigString("driverName") == "" {
|
||||||
|
if !util.FileExist("conf/app.conf") {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
dir = strings.ReplaceAll(dir, "\\", "/")
|
||||||
|
panic(fmt.Sprintf("The Casdoor config file: \"app.conf\" was not found, it should be placed at: \"%s/conf/app.conf\"", dir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if createDatabase {
|
if createDatabase {
|
||||||
err := createDatabaseForPostgres(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
|
err := createDatabaseForPostgres(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -62,7 +93,7 @@ func InitAdapter(createDatabase bool) {
|
|||||||
ormer.Engine.SetTableMapper(tbMapper)
|
ormer.Engine.SetTableMapper(tbMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTables(createDatabase bool) {
|
func CreateTables() {
|
||||||
if createDatabase {
|
if createDatabase {
|
||||||
err := ormer.CreateDatabase()
|
err := ormer.CreateDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -105,9 +136,14 @@ func NewAdapter(driverName string, dataSourceName string, dbName string) *Ormer
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func refineDataSourceNameForPostgres(dataSourceName string) string {
|
||||||
|
reg := regexp.MustCompile(`dbname=[^ ]+\s*`)
|
||||||
|
return reg.ReplaceAllString(dataSourceName, "")
|
||||||
|
}
|
||||||
|
|
||||||
func createDatabaseForPostgres(driverName string, dataSourceName string, dbName string) error {
|
func createDatabaseForPostgres(driverName string, dataSourceName string, dbName string) error {
|
||||||
if driverName == "postgres" {
|
if driverName == "postgres" {
|
||||||
db, err := sql.Open(driverName, dataSourceName)
|
db, err := sql.Open(driverName, refineDataSourceNameForPostgres(dataSourceName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -119,6 +155,21 @@ func createDatabaseForPostgres(driverName string, dataSourceName string, dbName
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
schema := util.GetValueFromDataSourceName("search_path", dataSourceName)
|
||||||
|
if schema != "" {
|
||||||
|
db, err = sql.Open(driverName, dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
_, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s;", schema))
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "already exists") {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
@@ -151,6 +202,12 @@ func (a *Ormer) open() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
if a.driverName == "postgres" {
|
||||||
|
schema := util.GetValueFromDataSourceName("search_path", dataSourceName)
|
||||||
|
if schema != "" {
|
||||||
|
engine.SetSchema(schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a.Engine = engine
|
a.Engine = engine
|
||||||
}
|
}
|
||||||
@@ -229,11 +286,6 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Record))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Webhook))
|
err = a.Engine.Sync2(new(Webhook))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -294,76 +346,3 @@ func (a *Ormer) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
|
||||||
session := ormer.Engine.Prepare()
|
|
||||||
if offset != -1 && limit != -1 {
|
|
||||||
session.Limit(limit, offset)
|
|
||||||
}
|
|
||||||
if owner != "" {
|
|
||||||
session = session.And("owner=?", owner)
|
|
||||||
}
|
|
||||||
if field != "" && value != "" {
|
|
||||||
if util.FilterField(field) {
|
|
||||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sortField == "" || sortOrder == "" {
|
|
||||||
sortField = "created_time"
|
|
||||||
}
|
|
||||||
if sortOrder == "ascend" {
|
|
||||||
session = session.Asc(util.SnakeString(sortField))
|
|
||||||
} else {
|
|
||||||
session = session.Desc(util.SnakeString(sortField))
|
|
||||||
}
|
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSessionForUser(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
|
||||||
session := ormer.Engine.Prepare()
|
|
||||||
if offset != -1 && limit != -1 {
|
|
||||||
session.Limit(limit, offset)
|
|
||||||
}
|
|
||||||
if owner != "" {
|
|
||||||
if offset == -1 {
|
|
||||||
session = session.And("owner=?", owner)
|
|
||||||
} else {
|
|
||||||
session = session.And("a.owner=?", owner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if field != "" && value != "" {
|
|
||||||
if util.FilterField(field) {
|
|
||||||
if offset != -1 {
|
|
||||||
field = fmt.Sprintf("a.%s", field)
|
|
||||||
}
|
|
||||||
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sortField == "" || sortOrder == "" {
|
|
||||||
sortField = "created_time"
|
|
||||||
}
|
|
||||||
|
|
||||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
|
||||||
tableName := tableNamePrefix + "user"
|
|
||||||
if offset == -1 {
|
|
||||||
if sortOrder == "ascend" {
|
|
||||||
session = session.Asc(util.SnakeString(sortField))
|
|
||||||
} else {
|
|
||||||
session = session.Desc(util.SnakeString(sortField))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if sortOrder == "ascend" {
|
|
||||||
session = session.Alias("a").
|
|
||||||
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
|
|
||||||
Select("b.*").
|
|
||||||
Asc("a." + util.SnakeString(sortField))
|
|
||||||
} else {
|
|
||||||
session = session.Alias("a").
|
|
||||||
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
|
|
||||||
Select("b.*").
|
|
||||||
Desc("a." + util.SnakeString(sortField))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
96
object/ormer_session.go
Normal file
96
object/ormer_session.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// 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/conf"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/xorm-io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
||||||
|
session := ormer.Engine.Prepare()
|
||||||
|
if offset != -1 && limit != -1 {
|
||||||
|
session.Limit(limit, offset)
|
||||||
|
}
|
||||||
|
if owner != "" {
|
||||||
|
session = session.And("owner=?", owner)
|
||||||
|
}
|
||||||
|
if field != "" && value != "" {
|
||||||
|
if util.FilterField(field) {
|
||||||
|
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sortField == "" || sortOrder == "" {
|
||||||
|
sortField = "created_time"
|
||||||
|
}
|
||||||
|
if sortOrder == "ascend" {
|
||||||
|
session = session.Asc(util.SnakeString(sortField))
|
||||||
|
} else {
|
||||||
|
session = session.Desc(util.SnakeString(sortField))
|
||||||
|
}
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSessionForUser(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
||||||
|
session := ormer.Engine.Prepare()
|
||||||
|
if offset != -1 && limit != -1 {
|
||||||
|
session.Limit(limit, offset)
|
||||||
|
}
|
||||||
|
if owner != "" {
|
||||||
|
if offset == -1 {
|
||||||
|
session = session.And("owner=?", owner)
|
||||||
|
} else {
|
||||||
|
session = session.And("a.owner=?", owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if field != "" && value != "" {
|
||||||
|
if util.FilterField(field) {
|
||||||
|
if offset != -1 {
|
||||||
|
field = fmt.Sprintf("a.%s", field)
|
||||||
|
}
|
||||||
|
session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sortField == "" || sortOrder == "" {
|
||||||
|
sortField = "created_time"
|
||||||
|
}
|
||||||
|
|
||||||
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
|
tableName := tableNamePrefix + "user"
|
||||||
|
if offset == -1 {
|
||||||
|
if sortOrder == "ascend" {
|
||||||
|
session = session.Asc(util.SnakeString(sortField))
|
||||||
|
} else {
|
||||||
|
session = session.Desc(util.SnakeString(sortField))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if sortOrder == "ascend" {
|
||||||
|
session = session.Alias("a").
|
||||||
|
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
|
||||||
|
Select("b.*").
|
||||||
|
Asc("a." + util.SnakeString(sortField))
|
||||||
|
} else {
|
||||||
|
session = session.Alias("a").
|
||||||
|
Join("INNER", []string{tableName, "b"}, "a.owner = b.owner and a.name = b.name").
|
||||||
|
Select("b.*").
|
||||||
|
Desc("a." + util.SnakeString(sortField))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
@@ -58,7 +58,7 @@ type PermissionRule struct {
|
|||||||
Id string `xorm:"varchar(100) index not null default ''" json:"id"`
|
Id string `xorm:"varchar(100) index not null default ''" json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const builtInAvailableField = 10
|
const builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
|
||||||
|
|
||||||
func (p *Permission) GetId() string {
|
func (p *Permission) GetId() string {
|
||||||
return util.GetId(p.Owner, p.Name)
|
return util.GetId(p.Owner, p.Name)
|
||||||
|
@@ -79,9 +79,7 @@ func (p *Permission) setEnforcerAdapter(enforcer *casbin.Enforcer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
driverName := conf.GetConfigString("driverName")
|
adapter, err := xormadapter.NewAdapterByEngineWithTableName(ormer.Engine, tableName, tableNamePrefix)
|
||||||
dataSourceName := conf.GetConfigRealDataSourceName(driverName)
|
|
||||||
adapter, err := xormadapter.NewAdapterWithTableName(driverName, dataSourceName, tableName, tableNamePrefix, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -309,8 +307,7 @@ func GetAllRoles(userId string) []string {
|
|||||||
|
|
||||||
func GetBuiltInModel(modelText string) (model.Model, error) {
|
func GetBuiltInModel(modelText string) (model.Model, error) {
|
||||||
if modelText == "" {
|
if modelText == "" {
|
||||||
modelText = `
|
modelText = `[request_definition]
|
||||||
[request_definition]
|
|
||||||
r = sub, obj, act
|
r = sub, obj, act
|
||||||
|
|
||||||
[policy_definition]
|
[policy_definition]
|
||||||
|
@@ -33,8 +33,8 @@ func getPermissionMap(owner string) (map[string]*Permission, error) {
|
|||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadPermissions(owner string, fileId string) (bool, error) {
|
func UploadPermissions(owner string, path string) (bool, error) {
|
||||||
table := xlsx.ReadXlsxFile(fileId)
|
table := xlsx.ReadXlsxFile(path)
|
||||||
|
|
||||||
oldUserMap, err := getPermissionMap(owner)
|
oldUserMap, err := getPermissionMap(owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -16,6 +16,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
@@ -28,15 +29,39 @@ type Plan struct {
|
|||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
PricePerMonth float64 `json:"pricePerMonth"`
|
Price float64 `json:"price"`
|
||||||
PricePerYear float64 `json:"pricePerYear"`
|
Currency string `xorm:"varchar(100)" json:"currency"`
|
||||||
Currency string `xorm:"varchar(100)" json:"currency"`
|
Period string `xorm:"varchar(100)" json:"period"`
|
||||||
IsEnabled bool `json:"isEnabled"`
|
Product string `xorm:"varchar(100)" json:"product"`
|
||||||
|
PaymentProviders []string `xorm:"varchar(100)" json:"paymentProviders"` // payment providers for related product
|
||||||
|
IsEnabled bool `json:"isEnabled"`
|
||||||
|
|
||||||
Role string `xorm:"varchar(100)" json:"role"`
|
Role string `xorm:"varchar(100)" json:"role"`
|
||||||
Options []string `xorm:"-" json:"options"`
|
Options []string `xorm:"-" json:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
PeriodMonthly = "Monthly"
|
||||||
|
PeriodYearly = "Yearly"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (plan *Plan) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", plan.Owner, plan.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDuration(period string) (startTime time.Time, endTime time.Time) {
|
||||||
|
if period == PeriodYearly {
|
||||||
|
startTime = time.Now()
|
||||||
|
endTime = startTime.AddDate(1, 0, 0)
|
||||||
|
} else if period == PeriodMonthly {
|
||||||
|
startTime = time.Now()
|
||||||
|
endTime = startTime.AddDate(0, 1, 0)
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("invalid period: %s", period))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func GetPlanCount(owner, field, value string) (int64, error) {
|
func GetPlanCount(owner, field, value string) (int64, error) {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
return session.Count(&Plan{})
|
return session.Count(&Plan{})
|
||||||
@@ -114,38 +139,3 @@ func DeletePlan(plan *Plan) (bool, error) {
|
|||||||
}
|
}
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plan *Plan) GetId() string {
|
|
||||||
return fmt.Sprintf("%s/%s", plan.Owner, plan.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Subscribe(owner string, user string, plan string, pricing string) (*Subscription, error) {
|
|
||||||
selectedPricing, err := GetPricing(fmt.Sprintf("%s/%s", owner, pricing))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
valid := selectedPricing != nil && selectedPricing.IsEnabled
|
|
||||||
|
|
||||||
if !valid {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
planBelongToPricing, err := selectedPricing.HasPlan(owner, plan)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if planBelongToPricing {
|
|
||||||
newSubscription := NewSubscription(owner, user, plan, selectedPricing.TrialDuration)
|
|
||||||
affected, err := AddSubscription(newSubscription)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if affected {
|
|
||||||
return newSubscription, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
@@ -16,7 +16,6 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
@@ -33,12 +32,26 @@ type Pricing struct {
|
|||||||
IsEnabled bool `json:"isEnabled"`
|
IsEnabled bool `json:"isEnabled"`
|
||||||
TrialDuration int `json:"trialDuration"`
|
TrialDuration int `json:"trialDuration"`
|
||||||
Application string `xorm:"varchar(100)" json:"application"`
|
Application string `xorm:"varchar(100)" json:"application"`
|
||||||
|
}
|
||||||
|
|
||||||
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
func (pricing *Pricing) GetId() string {
|
||||||
Approver string `xorm:"varchar(100)" json:"approver"`
|
return fmt.Sprintf("%s/%s", pricing.Owner, pricing.Name)
|
||||||
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
}
|
||||||
|
|
||||||
State string `xorm:"varchar(100)" json:"state"`
|
func (pricing *Pricing) HasPlan(planName string) (bool, error) {
|
||||||
|
planId := util.GetId(pricing.Owner, planName)
|
||||||
|
plan, err := GetPlan(planId)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if plan == nil {
|
||||||
|
return false, fmt.Errorf("plan: %s does not exist", planId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if util.InSlice(pricing.Plans, plan.Name) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPricingCount(owner, field, value string) (int64, error) {
|
func GetPricingCount(owner, field, value string) (int64, error) {
|
||||||
@@ -74,7 +87,7 @@ func getPricing(owner, name string) (*Pricing, error) {
|
|||||||
pricing := Pricing{Owner: owner, Name: name}
|
pricing := Pricing{Owner: owner, Name: name}
|
||||||
existed, err := ormer.Engine.Get(&pricing)
|
existed, err := ormer.Engine.Get(&pricing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &pricing, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if existed {
|
if existed {
|
||||||
return &pricing, nil
|
return &pricing, nil
|
||||||
@@ -88,6 +101,20 @@ func GetPricing(id string) (*Pricing, error) {
|
|||||||
return getPricing(owner, name)
|
return getPricing(owner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetApplicationDefaultPricing(owner, appName string) (*Pricing, error) {
|
||||||
|
pricings := make([]*Pricing, 0, 1)
|
||||||
|
err := ormer.Engine.Asc("created_time").Find(&pricings, &Pricing{Owner: owner, Application: appName})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pricing := range pricings {
|
||||||
|
if pricing.IsEnabled {
|
||||||
|
return pricing, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func UpdatePricing(id string, pricing *Pricing) (bool, error) {
|
func UpdatePricing(id string, pricing *Pricing) (bool, error) {
|
||||||
owner, name := util.GetOwnerAndNameFromId(id)
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
if p, err := getPricing(owner, name); err != nil {
|
if p, err := getPricing(owner, name); err != nil {
|
||||||
@@ -120,28 +147,21 @@ func DeletePricing(pricing *Pricing) (bool, error) {
|
|||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pricing *Pricing) GetId() string {
|
func CheckPricingAndPlan(owner, pricingName, planName string) error {
|
||||||
return fmt.Sprintf("%s/%s", pricing.Owner, pricing.Name)
|
pricingId := util.GetId(owner, pricingName)
|
||||||
}
|
pricing, err := GetPricing(pricingId)
|
||||||
|
if pricing == nil || err != nil {
|
||||||
func (pricing *Pricing) HasPlan(owner string, plan string) (bool, error) {
|
if pricing == nil && err == nil {
|
||||||
selectedPlan, err := GetPlan(fmt.Sprintf("%s/%s", owner, plan))
|
err = fmt.Errorf("pricing: %s does not exist", pricingName)
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if selectedPlan == nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result := false
|
|
||||||
|
|
||||||
for _, pricingPlan := range pricing.Plans {
|
|
||||||
if strings.Contains(pricingPlan, selectedPlan.Name) {
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
ok, err := pricing.HasPlan(planName)
|
||||||
return result, nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("pricing: %s does not have plan: %s", pricingName, planName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -141,24 +141,24 @@ func (product *Product) isValidProvider(provider *Provider) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (product *Product) getProvider(providerId string) (*Provider, error) {
|
func (product *Product) getProvider(providerName string) (*Provider, error) {
|
||||||
provider, err := getProvider(product.Owner, providerId)
|
provider, err := getProvider(product.Owner, providerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
return nil, fmt.Errorf("the payment provider: %s does not exist", providerId)
|
return nil, fmt.Errorf("the payment provider: %s does not exist", providerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !product.isValidProvider(provider) {
|
if !product.isValidProvider(provider) {
|
||||||
return nil, fmt.Errorf("the payment provider: %s is not valid for the product: %s", providerId, product.Name)
|
return nil, fmt.Errorf("the payment provider: %s is not valid for the product: %s", providerName, product.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuyProduct(id string, providerName string, user *User, host string) (string, string, error) {
|
func BuyProduct(id string, user *User, providerName, pricingName, planName, host string) (string, string, error) {
|
||||||
product, err := GetProduct(id)
|
product, err := GetProduct(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
@@ -181,13 +181,31 @@ func BuyProduct(id string, providerName string, user *User, host string) (string
|
|||||||
owner := product.Owner
|
owner := product.Owner
|
||||||
productName := product.Name
|
productName := product.Name
|
||||||
payerName := fmt.Sprintf("%s | %s", user.Name, user.DisplayName)
|
payerName := fmt.Sprintf("%s | %s", user.Name, user.DisplayName)
|
||||||
paymentName := util.GenerateTimeId()
|
paymentName := fmt.Sprintf("payment_%v", util.GenerateTimeId())
|
||||||
productDisplayName := product.DisplayName
|
productDisplayName := product.DisplayName
|
||||||
|
|
||||||
originFrontend, originBackend := getOriginFromHost(host)
|
originFrontend, originBackend := getOriginFromHost(host)
|
||||||
returnUrl := fmt.Sprintf("%s/payments/%s/%s/result", originFrontend, owner, paymentName)
|
returnUrl := fmt.Sprintf("%s/payments/%s/%s/result", originFrontend, owner, paymentName)
|
||||||
notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s", originBackend, owner, paymentName)
|
notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s", originBackend, owner, paymentName)
|
||||||
// Create an Order and get the payUrl
|
if user.Type == "paid-user" {
|
||||||
|
// Create a subscription for `paid-user`
|
||||||
|
if pricingName != "" && planName != "" {
|
||||||
|
plan, err := GetPlan(util.GetId(owner, planName))
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if plan == nil {
|
||||||
|
return "", "", fmt.Errorf("the plan: %s does not exist", planName)
|
||||||
|
}
|
||||||
|
sub := NewSubscription(owner, user.Name, plan.Name, paymentName, plan.Period)
|
||||||
|
_, err = AddSubscription(sub)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
returnUrl = fmt.Sprintf("%s/buy-plan/%s/%s/result?subscription=%s", originFrontend, owner, pricingName, sub.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create an OrderId and get the payUrl
|
||||||
payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
|
payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
@@ -228,7 +246,6 @@ func BuyProduct(id string, providerName string, user *User, host string) (string
|
|||||||
if !affected {
|
if !affected {
|
||||||
return "", "", fmt.Errorf("failed to add payment: %s", util.StructToJson(payment))
|
return "", "", fmt.Errorf("failed to add payment: %s", util.StructToJson(payment))
|
||||||
}
|
}
|
||||||
|
|
||||||
return payUrl, orderId, err
|
return payUrl, orderId, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,3 +269,38 @@ func ExtendProductWithProviders(product *Product) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateProductForPlan(plan *Plan) *Product {
|
||||||
|
product := &Product{
|
||||||
|
Owner: plan.Owner,
|
||||||
|
Name: fmt.Sprintf("product_%v", util.GetRandomName()),
|
||||||
|
DisplayName: fmt.Sprintf("Product for Plan %v/%v/%v", plan.Name, plan.DisplayName, plan.Period),
|
||||||
|
CreatedTime: plan.CreatedTime,
|
||||||
|
|
||||||
|
Image: "https://cdn.casbin.org/img/casdoor-logo_1185x256.png", // TODO
|
||||||
|
Detail: fmt.Sprintf("This product was auto created for plan %v(%v), subscription period is %v", plan.Name, plan.DisplayName, plan.Period),
|
||||||
|
Description: plan.Description,
|
||||||
|
Tag: "auto_created_product_for_plan",
|
||||||
|
Price: plan.Price,
|
||||||
|
Currency: plan.Currency,
|
||||||
|
|
||||||
|
Quantity: 999,
|
||||||
|
Sold: 0,
|
||||||
|
|
||||||
|
Providers: plan.PaymentProviders,
|
||||||
|
State: "Published",
|
||||||
|
}
|
||||||
|
if product.Providers == nil {
|
||||||
|
product.Providers = []string{}
|
||||||
|
}
|
||||||
|
return product
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateProductForPlan(plan *Plan, product *Product) {
|
||||||
|
product.Owner = plan.Owner
|
||||||
|
product.DisplayName = fmt.Sprintf("Product for Plan %v/%v/%v", plan.Name, plan.DisplayName, plan.Period)
|
||||||
|
product.Detail = fmt.Sprintf("This product was auto created for plan %v(%v), subscription period is %v", plan.Name, plan.DisplayName, plan.Period)
|
||||||
|
product.Price = plan.Price
|
||||||
|
product.Currency = plan.Currency
|
||||||
|
product.Providers = plan.PaymentProviders
|
||||||
|
}
|
||||||
|
@@ -36,7 +36,7 @@ type Provider struct {
|
|||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
SubType string `xorm:"varchar(100)" json:"subType"`
|
SubType string `xorm:"varchar(100)" json:"subType"`
|
||||||
Method string `xorm:"varchar(100)" json:"method"`
|
Method string `xorm:"varchar(100)" json:"method"`
|
||||||
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
ClientId string `xorm:"varchar(200)" json:"clientId"`
|
||||||
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
|
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
|
||||||
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
|
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
|
||||||
ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
|
ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
|
||||||
@@ -254,7 +254,8 @@ func DeleteProvider(provider *Provider) (bool, error) {
|
|||||||
func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
||||||
cert := &Cert{}
|
cert := &Cert{}
|
||||||
if p.Cert != "" {
|
if p.Cert != "" {
|
||||||
cert, err := getCert(p.Owner, p.Cert)
|
var err error
|
||||||
|
cert, err = getCert(p.Owner, p.Cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/beego/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logPostOnly bool
|
var logPostOnly bool
|
||||||
@@ -30,26 +31,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Record struct {
|
type Record struct {
|
||||||
Id int `xorm:"int notnull pk autoincr" json:"id"`
|
casvisorsdk.Record
|
||||||
|
|
||||||
Owner string `xorm:"varchar(100) index" json:"owner"`
|
|
||||||
Name string `xorm:"varchar(100) index" json:"name"`
|
|
||||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
|
||||||
|
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
|
||||||
ClientIp string `xorm:"varchar(100)" json:"clientIp"`
|
|
||||||
User string `xorm:"varchar(100)" json:"user"`
|
|
||||||
Method string `xorm:"varchar(100)" json:"method"`
|
|
||||||
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
|
|
||||||
Action string `xorm:"varchar(1000)" json:"action"`
|
|
||||||
|
|
||||||
Object string `xorm:"-" json:"object"`
|
|
||||||
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
|
||||||
|
|
||||||
IsTriggered bool `json:"isTriggered"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRecord(ctx *context.Context) *Record {
|
func NewRecord(ctx *context.Context) *casvisorsdk.Record {
|
||||||
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
|
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
|
||||||
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
|
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
|
||||||
requestUri := util.FilterQuery(ctx.Request.RequestURI, []string{"accessToken"})
|
requestUri := util.FilterQuery(ctx.Request.RequestURI, []string{"accessToken"})
|
||||||
@@ -62,7 +47,7 @@ func NewRecord(ctx *context.Context) *Record {
|
|||||||
object = string(ctx.Input.RequestBody)
|
object = string(ctx.Input.RequestBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
record := Record{
|
record := casvisorsdk.Record{
|
||||||
Name: util.GenerateId(),
|
Name: util.GenerateId(),
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
ClientIp: ip,
|
ClientIp: ip,
|
||||||
@@ -76,7 +61,7 @@ func NewRecord(ctx *context.Context) *Record {
|
|||||||
return &record
|
return &record
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddRecord(record *Record) bool {
|
func AddRecord(record *casvisorsdk.Record) bool {
|
||||||
if logPostOnly {
|
if logPostOnly {
|
||||||
if record.Method == "GET" {
|
if record.Method == "GET" {
|
||||||
return false
|
return false
|
||||||
@@ -96,51 +81,19 @@ func AddRecord(record *Record) bool {
|
|||||||
fmt.Println(errWebhook)
|
fmt.Println(errWebhook)
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := ormer.Engine.Insert(record)
|
if casvisorsdk.GetClient() == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := casvisorsdk.AddRecord(record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return affected != 0
|
return affected
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRecordCount(field, value string, filterRecord *Record) (int64, error) {
|
func SendWebhooks(record *casvisorsdk.Record) error {
|
||||||
session := GetSession("", -1, -1, field, value, "", "")
|
|
||||||
return session.Count(filterRecord)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRecords() ([]*Record, error) {
|
|
||||||
records := []*Record{}
|
|
||||||
err := ormer.Engine.Desc("id").Find(&records)
|
|
||||||
if err != nil {
|
|
||||||
return records, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return records, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder string, filterRecord *Record) ([]*Record, error) {
|
|
||||||
records := []*Record{}
|
|
||||||
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
|
||||||
err := session.Find(&records, filterRecord)
|
|
||||||
if err != nil {
|
|
||||||
return records, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return records, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRecordsByField(record *Record) ([]*Record, error) {
|
|
||||||
records := []*Record{}
|
|
||||||
err := ormer.Engine.Find(&records, record)
|
|
||||||
if err != nil {
|
|
||||||
return records, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return records, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendWebhooks(record *Record) error {
|
|
||||||
webhooks, err := getWebhooksByOrganization(record.Organization)
|
webhooks, err := getWebhooksByOrganization(record.Organization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -160,17 +113,16 @@ func SendWebhooks(record *Record) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if matched {
|
if matched {
|
||||||
|
var user *User
|
||||||
if webhook.IsUserExtended {
|
if webhook.IsUserExtended {
|
||||||
user, err := getUser(record.Organization, record.User)
|
user, err = getUser(record.Organization, record.User)
|
||||||
user, err = GetMaskedUser(user, false, err)
|
user, err = GetMaskedUser(user, false, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
record.ExtendedUser = user
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sendWebhook(webhook, record)
|
err = sendWebhook(webhook, record, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
50
object/record_casvisor.go
Normal file
50
object/record_casvisor.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCasvisorApplication() *Application {
|
||||||
|
applications, err := GetApplications("admin")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, application := range applications {
|
||||||
|
if strings.Contains(strings.ToLower(application.Name), "casvisor") {
|
||||||
|
return application
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitCasvisorConfig() {
|
||||||
|
application := getCasvisorApplication()
|
||||||
|
if application == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
casvisorEndpoint := application.HomepageUrl
|
||||||
|
clientId := application.ClientId
|
||||||
|
clientSecret := application.ClientSecret
|
||||||
|
casdoorOrganization := application.Organization
|
||||||
|
casdoorApplication := application.Name
|
||||||
|
|
||||||
|
casvisorsdk.InitConfig(casvisorEndpoint, clientId, clientSecret, casdoorOrganization, casdoorApplication)
|
||||||
|
}
|
@@ -33,8 +33,8 @@ func getRoleMap(owner string) (map[string]*Role, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadRoles(owner string, fileId string) (bool, error) {
|
func UploadRoles(owner string, path string) (bool, error) {
|
||||||
table := xlsx.ReadXlsxFile(fileId)
|
table := xlsx.ReadXlsxFile(path)
|
||||||
|
|
||||||
oldUserMap, err := getRoleMap(owner)
|
oldUserMap, err := getRoleMap(owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -31,8 +31,8 @@ import (
|
|||||||
"github.com/RobotsAndPencils/go-saml"
|
"github.com/RobotsAndPencils/go-saml"
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"github.com/google/uuid"
|
||||||
dsig "github.com/russellhaering/goxmldsig"
|
dsig "github.com/russellhaering/goxmldsig"
|
||||||
uuid "github.com/satori/go.uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSamlResponse
|
// NewSamlResponse
|
||||||
@@ -46,7 +46,7 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
|
|||||||
expireTime := time.Now().UTC().Add(time.Hour * 24).Format(time.RFC3339)
|
expireTime := time.Now().UTC().Add(time.Hour * 24).Format(time.RFC3339)
|
||||||
samlResponse.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
|
samlResponse.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
|
||||||
samlResponse.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
|
samlResponse.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
|
||||||
arId := uuid.NewV4()
|
arId := uuid.New()
|
||||||
|
|
||||||
samlResponse.CreateAttr("ID", fmt.Sprintf("_%s", arId))
|
samlResponse.CreateAttr("ID", fmt.Sprintf("_%s", arId))
|
||||||
samlResponse.CreateAttr("Version", "2.0")
|
samlResponse.CreateAttr("Version", "2.0")
|
||||||
@@ -60,7 +60,7 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
|
|||||||
assertion := samlResponse.CreateElement("saml:Assertion")
|
assertion := samlResponse.CreateElement("saml:Assertion")
|
||||||
assertion.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
assertion.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
assertion.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
|
assertion.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
|
||||||
assertion.CreateAttr("ID", fmt.Sprintf("_%s", uuid.NewV4()))
|
assertion.CreateAttr("ID", fmt.Sprintf("_%s", uuid.New()))
|
||||||
assertion.CreateAttr("Version", "2.0")
|
assertion.CreateAttr("Version", "2.0")
|
||||||
assertion.CreateAttr("IssueInstant", now)
|
assertion.CreateAttr("IssueInstant", now)
|
||||||
assertion.CreateElement("saml:Issuer").SetText(host)
|
assertion.CreateElement("saml:Issuer").SetText(host)
|
||||||
@@ -82,7 +82,7 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
|
|||||||
}
|
}
|
||||||
authnStatement := assertion.CreateElement("saml:AuthnStatement")
|
authnStatement := assertion.CreateElement("saml:AuthnStatement")
|
||||||
authnStatement.CreateAttr("AuthnInstant", now)
|
authnStatement.CreateAttr("AuthnInstant", now)
|
||||||
authnStatement.CreateAttr("SessionIndex", fmt.Sprintf("_%s", uuid.NewV4()))
|
authnStatement.CreateAttr("SessionIndex", fmt.Sprintf("_%s", uuid.New()))
|
||||||
authnStatement.CreateAttr("SessionNotOnOrAfter", expireTime)
|
authnStatement.CreateAttr("SessionNotOnOrAfter", expireTime)
|
||||||
authnStatement.CreateElement("saml:AuthnContext").CreateElement("saml:AuthnContextClassRef").SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")
|
authnStatement.CreateElement("saml:AuthnContext").CreateElement("saml:AuthnContextClassRef").SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")
|
||||||
|
|
||||||
@@ -355,7 +355,7 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
|||||||
samlResponse.CreateAttr("MajorVersion", "1")
|
samlResponse.CreateAttr("MajorVersion", "1")
|
||||||
samlResponse.CreateAttr("MinorVersion", "1")
|
samlResponse.CreateAttr("MinorVersion", "1")
|
||||||
|
|
||||||
responseID := uuid.NewV4()
|
responseID := uuid.New()
|
||||||
samlResponse.CreateAttr("ResponseID", fmt.Sprintf("_%s", responseID))
|
samlResponse.CreateAttr("ResponseID", fmt.Sprintf("_%s", responseID))
|
||||||
samlResponse.CreateAttr("InResponseTo", requestID)
|
samlResponse.CreateAttr("InResponseTo", requestID)
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
|||||||
assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:1.0:assertion")
|
assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:1.0:assertion")
|
||||||
assertion.CreateAttr("MajorVersion", "1")
|
assertion.CreateAttr("MajorVersion", "1")
|
||||||
assertion.CreateAttr("MinorVersion", "1")
|
assertion.CreateAttr("MinorVersion", "1")
|
||||||
assertion.CreateAttr("AssertionID", uuid.NewV4().String())
|
assertion.CreateAttr("AssertionID", uuid.New().String())
|
||||||
assertion.CreateAttr("Issuer", host)
|
assertion.CreateAttr("Issuer", host)
|
||||||
assertion.CreateAttr("IssueInstant", now)
|
assertion.CreateAttr("IssueInstant", now)
|
||||||
|
|
||||||
|
@@ -18,47 +18,108 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/pp"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultStatus = "Pending"
|
type SubscriptionState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SubStatePending SubscriptionState = "Pending"
|
||||||
|
SubStateError SubscriptionState = "Error"
|
||||||
|
SubStateSuspended SubscriptionState = "Suspended" // suspended by the admin
|
||||||
|
|
||||||
|
SubStateActive SubscriptionState = "Active"
|
||||||
|
SubStateUpcoming SubscriptionState = "Upcoming"
|
||||||
|
SubStateExpired SubscriptionState = "Expired"
|
||||||
|
)
|
||||||
|
|
||||||
type Subscription struct {
|
type Subscription struct {
|
||||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
|
||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
StartDate time.Time `json:"startDate"`
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
EndDate time.Time `json:"endDate"`
|
Pricing string `xorm:"varchar(100)" json:"pricing"`
|
||||||
Duration int `json:"duration"`
|
Plan string `xorm:"varchar(100)" json:"plan"`
|
||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Payment string `xorm:"varchar(100)" json:"payment"`
|
||||||
|
|
||||||
User string `xorm:"mediumtext" json:"user"`
|
StartTime time.Time `json:"startTime"`
|
||||||
Plan string `xorm:"varchar(100)" json:"plan"`
|
EndTime time.Time `json:"endTime"`
|
||||||
|
Period string `xorm:"varchar(100)" json:"period"`
|
||||||
IsEnabled bool `json:"isEnabled"`
|
State SubscriptionState `xorm:"varchar(100)" json:"state"`
|
||||||
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
|
||||||
Approver string `xorm:"varchar(100)" json:"approver"`
|
|
||||||
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
|
||||||
|
|
||||||
State string `xorm:"varchar(100)" json:"state"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubscription(owner string, user string, plan string, duration int) *Subscription {
|
func (sub *Subscription) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", sub.Owner, sub.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub *Subscription) UpdateState() error {
|
||||||
|
preState := sub.State
|
||||||
|
// update subscription state by payment state
|
||||||
|
if sub.State == SubStatePending {
|
||||||
|
if sub.Payment == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
payment, err := GetPayment(util.GetId(sub.Owner, sub.Payment))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if payment == nil {
|
||||||
|
sub.Description = fmt.Sprintf("payment: %s does not exist", sub.Payment)
|
||||||
|
sub.State = SubStateError
|
||||||
|
} else {
|
||||||
|
if payment.State == pp.PaymentStatePaid {
|
||||||
|
sub.State = SubStateActive
|
||||||
|
} else if payment.State != pp.PaymentStateCreated {
|
||||||
|
// other states: Canceled, Timeout, Error
|
||||||
|
sub.Description = fmt.Sprintf("payment: %s state is %v", sub.Payment, payment.State)
|
||||||
|
sub.State = SubStateError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sub.State == SubStateActive || sub.State == SubStateUpcoming || sub.State == SubStateExpired {
|
||||||
|
if sub.EndTime.Before(time.Now()) {
|
||||||
|
sub.State = SubStateExpired
|
||||||
|
} else if sub.StartTime.After(time.Now()) {
|
||||||
|
sub.State = SubStateUpcoming
|
||||||
|
} else {
|
||||||
|
sub.State = SubStateActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if preState != sub.State {
|
||||||
|
_, err := UpdateSubscription(sub.GetId(), sub)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubscription(owner, userName, planName, paymentName, period string) *Subscription {
|
||||||
|
startTime, endTime := GetDuration(period)
|
||||||
id := util.GenerateId()[:6]
|
id := util.GenerateId()[:6]
|
||||||
return &Subscription{
|
return &Subscription{
|
||||||
Name: "Subscription_" + id,
|
|
||||||
DisplayName: "New Subscription - " + id,
|
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
User: owner + "/" + user,
|
Name: "sub_" + id,
|
||||||
Plan: owner + "/" + plan,
|
DisplayName: "New Subscription - " + id,
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
State: defaultStatus,
|
|
||||||
Duration: duration,
|
User: userName,
|
||||||
StartDate: time.Now(),
|
Plan: planName,
|
||||||
EndDate: time.Now().AddDate(0, 0, duration),
|
Payment: paymentName,
|
||||||
|
|
||||||
|
StartTime: startTime,
|
||||||
|
EndTime: endTime,
|
||||||
|
Period: period,
|
||||||
|
State: SubStatePending, // waiting for payment complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +134,28 @@ func GetSubscriptions(owner string) ([]*Subscription, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return subscriptions, err
|
return subscriptions, err
|
||||||
}
|
}
|
||||||
|
for _, sub := range subscriptions {
|
||||||
|
err = sub.UpdateState()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subscriptions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscriptionsByUser(owner, userName string) ([]*Subscription, error) {
|
||||||
|
subscriptions := []*Subscription{}
|
||||||
|
err := ormer.Engine.Desc("created_time").Find(&subscriptions, &Subscription{Owner: owner, User: userName})
|
||||||
|
if err != nil {
|
||||||
|
return subscriptions, err
|
||||||
|
}
|
||||||
|
// update subscription state
|
||||||
|
for _, sub := range subscriptions {
|
||||||
|
err = sub.UpdateState()
|
||||||
|
if err != nil {
|
||||||
|
return subscriptions, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return subscriptions, nil
|
return subscriptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +166,12 @@ func GetPaginationSubscriptions(owner string, offset, limit int, field, value, s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return subscriptions, err
|
return subscriptions, err
|
||||||
}
|
}
|
||||||
|
for _, sub := range subscriptions {
|
||||||
|
err = sub.UpdateState()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return subscriptions, nil
|
return subscriptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +231,3 @@ func DeleteSubscription(subscription *Subscription) (bool, error) {
|
|||||||
|
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (subscription *Subscription) GetId() string {
|
|
||||||
return fmt.Sprintf("%s/%s", subscription.Owner, subscription.Name)
|
|
||||||
}
|
|
||||||
|
@@ -25,6 +25,7 @@ type TableColumn struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
CasdoorName string `json:"casdoorName"`
|
CasdoorName string `json:"casdoorName"`
|
||||||
|
IsKey bool `json:"isKey"`
|
||||||
IsHashed bool `json:"isHashed"`
|
IsHashed bool `json:"isHashed"`
|
||||||
Values []string `json:"values"`
|
Values []string `json:"values"`
|
||||||
}
|
}
|
||||||
@@ -36,15 +37,15 @@ type Syncer struct {
|
|||||||
|
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
|
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
||||||
|
SslMode string `xorm:"varchar(100)" json:"sslMode"`
|
||||||
|
|
||||||
Host string `xorm:"varchar(100)" json:"host"`
|
Host string `xorm:"varchar(100)" json:"host"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
User string `xorm:"varchar(100)" json:"user"`
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
Password string `xorm:"varchar(100)" json:"password"`
|
Password string `xorm:"varchar(100)" json:"password"`
|
||||||
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
|
||||||
Database string `xorm:"varchar(100)" json:"database"`
|
Database string `xorm:"varchar(100)" json:"database"`
|
||||||
Table string `xorm:"varchar(100)" json:"table"`
|
Table string `xorm:"varchar(100)" json:"table"`
|
||||||
TablePrimaryKey string `xorm:"varchar(100)" json:"tablePrimaryKey"`
|
|
||||||
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
||||||
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
|
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
|
||||||
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"`
|
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"`
|
||||||
@@ -229,7 +230,28 @@ func (syncer *Syncer) getTable() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunSyncer(syncer *Syncer) {
|
func (syncer *Syncer) getKey() string {
|
||||||
syncer.initAdapter()
|
key := "id"
|
||||||
syncer.syncUsers()
|
hasKey := false
|
||||||
|
hasId := false
|
||||||
|
for _, tableColumn := range syncer.TableColumns {
|
||||||
|
if tableColumn.IsKey {
|
||||||
|
hasKey = true
|
||||||
|
key = tableColumn.Name
|
||||||
|
}
|
||||||
|
if tableColumn.Name == "id" {
|
||||||
|
hasId = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasKey && !hasId {
|
||||||
|
key = syncer.TableColumns[0].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunSyncer(syncer *Syncer) error {
|
||||||
|
syncer.initAdapter()
|
||||||
|
return syncer.syncUsers()
|
||||||
}
|
}
|
||||||
|
@@ -52,11 +52,14 @@ func addSyncerJob(syncer *Syncer) error {
|
|||||||
|
|
||||||
syncer.initAdapter()
|
syncer.initAdapter()
|
||||||
|
|
||||||
syncer.syncUsers()
|
err := syncer.syncUsers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
schedule := fmt.Sprintf("@every %ds", syncer.SyncInterval)
|
schedule := fmt.Sprintf("@every %ds", syncer.SyncInterval)
|
||||||
cron := getCronMap(syncer.Name)
|
cron := getCronMap(syncer.Name)
|
||||||
_, err := cron.AddFunc(schedule, syncer.syncUsers)
|
_, err = cron.AddFunc(schedule, syncer.syncUsersNoError)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -19,18 +19,24 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (syncer *Syncer) syncUsers() {
|
func (syncer *Syncer) syncUsers() error {
|
||||||
|
if len(syncer.TableColumns) == 0 {
|
||||||
|
return fmt.Errorf("The syncer table columns should not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("Running syncUsers()..\n")
|
fmt.Printf("Running syncUsers()..\n")
|
||||||
|
|
||||||
users, userMap, userNameMap := syncer.getUserMap()
|
users, _, _ := syncer.getUserMap()
|
||||||
oUsers, oUserMap, err := syncer.getOriginalUserMap()
|
oUsers, _, err := syncer.getOriginalUserMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(err.Error())
|
fmt.Printf(err.Error())
|
||||||
|
|
||||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
|
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
|
||||||
updateSyncerErrorText(syncer, line)
|
_, err = updateSyncerErrorText(syncer, line)
|
||||||
return
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Users: %d, oUsers: %d\n", len(users), len(oUsers))
|
fmt.Printf("Users: %d, oUsers: %d\n", len(users), len(oUsers))
|
||||||
@@ -40,49 +46,77 @@ func (syncer *Syncer) syncUsers() {
|
|||||||
_, affiliationMap, err = syncer.getAffiliationMap()
|
_, affiliationMap, err = syncer.getAffiliationMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key := syncer.getKey()
|
||||||
|
|
||||||
|
myUsers := map[string]*User{}
|
||||||
|
for _, m := range users {
|
||||||
|
myUsers[syncer.getUserValue(m, key)] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
myOUsers := map[string]*User{}
|
||||||
|
for _, m := range oUsers {
|
||||||
|
myOUsers[syncer.getUserValue(m, key)] = m
|
||||||
|
}
|
||||||
|
|
||||||
newUsers := []*User{}
|
newUsers := []*User{}
|
||||||
for _, oUser := range oUsers {
|
for _, oUser := range oUsers {
|
||||||
id := oUser.Id
|
primary := syncer.getUserValue(oUser, key)
|
||||||
if _, ok := userMap[id]; !ok {
|
|
||||||
if _, ok := userNameMap[oUser.Name]; !ok {
|
|
||||||
newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
|
||||||
fmt.Printf("New user: %v\n", newUser)
|
|
||||||
newUsers = append(newUsers, newUser)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
user := userMap[id]
|
|
||||||
oHash := syncer.calculateHash(oUser)
|
|
||||||
|
|
||||||
|
if _, ok := myUsers[primary]; !ok {
|
||||||
|
newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
||||||
|
fmt.Printf("New user: %v\n", newUser)
|
||||||
|
newUsers = append(newUsers, newUser)
|
||||||
|
} else {
|
||||||
|
user := myUsers[primary]
|
||||||
|
oHash := syncer.calculateHash(oUser)
|
||||||
if user.Hash == user.PreHash {
|
if user.Hash == user.PreHash {
|
||||||
if user.Hash != oHash {
|
if user.Hash != oHash {
|
||||||
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
||||||
updatedUser.Hash = oHash
|
updatedUser.Hash = oHash
|
||||||
updatedUser.PreHash = oHash
|
updatedUser.PreHash = oHash
|
||||||
syncer.updateUserForOriginalFields(updatedUser)
|
|
||||||
fmt.Printf("Update from oUser to user: %v\n", updatedUser)
|
fmt.Printf("Update from oUser to user: %v\n", updatedUser)
|
||||||
|
_, err = syncer.updateUserForOriginalByFields(updatedUser, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if user.PreHash == oHash {
|
if user.PreHash == oHash {
|
||||||
if !syncer.IsReadOnly {
|
if !syncer.IsReadOnly {
|
||||||
updatedOUser := syncer.createOriginalUserFromUser(user)
|
updatedOUser := syncer.createOriginalUserFromUser(user)
|
||||||
syncer.updateUser(updatedOUser)
|
|
||||||
fmt.Printf("Update from user to oUser: %v\n", updatedOUser)
|
fmt.Printf("Update from user to oUser: %v\n", updatedOUser)
|
||||||
|
_, err = syncer.updateUser(updatedOUser)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update preHash
|
// update preHash
|
||||||
user.PreHash = user.Hash
|
user.PreHash = user.Hash
|
||||||
SetUserField(user, "pre_hash", user.PreHash)
|
_, err = SetUserField(user, "pre_hash", user.PreHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if user.Hash == oHash {
|
if user.Hash == oHash {
|
||||||
// update preHash
|
// update preHash
|
||||||
user.PreHash = user.Hash
|
user.PreHash = user.Hash
|
||||||
SetUserField(user, "pre_hash", user.PreHash)
|
_, err = SetUserField(user, "pre_hash", user.PreHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
|
||||||
updatedUser.Hash = oHash
|
updatedUser.Hash = oHash
|
||||||
updatedUser.PreHash = oHash
|
updatedUser.PreHash = oHash
|
||||||
syncer.updateUserForOriginalFields(updatedUser)
|
|
||||||
fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser)
|
fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser)
|
||||||
|
_, err = syncer.updateUserForOriginalByFields(updatedUser, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,20 +124,30 @@ func (syncer *Syncer) syncUsers() {
|
|||||||
}
|
}
|
||||||
_, err = AddUsersInBatch(newUsers)
|
_, err = AddUsersInBatch(newUsers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !syncer.IsReadOnly {
|
if !syncer.IsReadOnly {
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
id := user.Id
|
primary := syncer.getUserValue(user, key)
|
||||||
if _, ok := oUserMap[id]; !ok {
|
if _, ok := myOUsers[primary]; !ok {
|
||||||
newOUser := syncer.createOriginalUserFromUser(user)
|
newOUser := syncer.createOriginalUserFromUser(user)
|
||||||
|
|
||||||
|
fmt.Printf("New oUser: %v\n", newOUser)
|
||||||
_, err = syncer.addUser(newOUser)
|
_, err = syncer.addUser(newOUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("New oUser: %v\n", newOUser)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) syncUsersNoError() {
|
||||||
|
err := syncer.syncUsers()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("syncUsersNoError() error: %s\n", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,8 +31,8 @@ type Credential struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) {
|
func (syncer *Syncer) getOriginalUsers() ([]*OriginalUser, error) {
|
||||||
sql := fmt.Sprintf("select * from %s", syncer.getTable())
|
var results []map[string]string
|
||||||
results, err := syncer.Ormer.Engine.QueryString(sql)
|
err := syncer.Ormer.Engine.Table(syncer.getTable()).Find(&results)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -64,32 +64,13 @@ func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*Origina
|
|||||||
|
|
||||||
func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
|
func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
|
||||||
m := syncer.getMapFromOriginalUser(user)
|
m := syncer.getMapFromOriginalUser(user)
|
||||||
keyString, valueString := syncer.getSqlKeyValueStringFromMap(m)
|
affected, err := syncer.Ormer.Engine.Table(syncer.getTable()).Insert(m)
|
||||||
|
|
||||||
sql := fmt.Sprintf("insert into %s (%s) values (%s)", syncer.getTable(), keyString, valueString)
|
|
||||||
res, err := syncer.Ormer.Engine.Exec(sql)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := res.RowsAffected()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (syncer *Syncer) getOriginalColumns() []string {
|
|
||||||
res := []string{}
|
|
||||||
for _, tableColumn := range syncer.TableColumns {
|
|
||||||
if tableColumn.CasdoorName != "Id" {
|
|
||||||
res = append(res, tableColumn.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func (syncer *Syncer) getCasdoorColumns() []string {
|
func (syncer *Syncer) getCasdoorColumns() []string {
|
||||||
res := []string{}
|
res := []string{}
|
||||||
for _, tableColumn := range syncer.TableColumns {
|
for _, tableColumn := range syncer.TableColumns {
|
||||||
@@ -102,22 +83,15 @@ func (syncer *Syncer) getCasdoorColumns() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
|
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
|
||||||
|
key := syncer.getKey()
|
||||||
m := syncer.getMapFromOriginalUser(user)
|
m := syncer.getMapFromOriginalUser(user)
|
||||||
pkValue := m[syncer.TablePrimaryKey]
|
pkValue := m[key]
|
||||||
delete(m, syncer.TablePrimaryKey)
|
delete(m, key)
|
||||||
setString := syncer.getSqlSetStringFromMap(m)
|
|
||||||
|
|
||||||
sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, syncer.TablePrimaryKey, pkValue)
|
affected, err := syncer.Ormer.Engine.Table(syncer.getTable()).ID(pkValue).Update(&m)
|
||||||
res, err := syncer.Ormer.Engine.Exec(sql)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := res.RowsAffected()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +116,34 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
return affected != 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) updateUserForOriginalByFields(user *User, key string) (bool, error) {
|
||||||
|
var err error
|
||||||
|
oldUser := User{}
|
||||||
|
|
||||||
|
existed, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(user, key), user.Owner).Get(&oldUser)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !existed {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
||||||
|
user.PermanentAvatar, err = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
columns := syncer.getCasdoorColumns()
|
||||||
|
columns = append(columns, "affiliation", "hash", "pre_hash")
|
||||||
|
affected, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(&oldUser, key), oldUser.Owner).Cols(columns...).Update(user)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
@@ -165,7 +167,11 @@ func (syncer *Syncer) initAdapter() {
|
|||||||
if syncer.DatabaseType == "mssql" {
|
if syncer.DatabaseType == "mssql" {
|
||||||
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, syncer.Database)
|
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, syncer.Database)
|
||||||
} else if syncer.DatabaseType == "postgres" {
|
} else if syncer.DatabaseType == "postgres" {
|
||||||
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, syncer.Database)
|
sslMode := "disable"
|
||||||
|
if syncer.SslMode != "" {
|
||||||
|
sslMode = syncer.SslMode
|
||||||
|
}
|
||||||
|
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=%s dbname=%s", syncer.User, syncer.Password, syncer.Host, syncer.Port, sslMode, syncer.Database)
|
||||||
} else {
|
} else {
|
||||||
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", syncer.User, syncer.Password, syncer.Host, syncer.Port)
|
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", syncer.User, syncer.Password, syncer.Host, syncer.Port)
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package object
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -153,14 +154,45 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) {
|
|||||||
user.IsOnline = util.ParseBool(value)
|
user.IsOnline = util.ParseBool(value)
|
||||||
case "IsAdmin":
|
case "IsAdmin":
|
||||||
user.IsAdmin = util.ParseBool(value)
|
user.IsAdmin = util.ParseBool(value)
|
||||||
case "IsGlobalAdmin":
|
|
||||||
user.IsGlobalAdmin = util.ParseBool(value)
|
|
||||||
case "IsForbidden":
|
case "IsForbidden":
|
||||||
user.IsForbidden = util.ParseBool(value)
|
user.IsForbidden = util.ParseBool(value)
|
||||||
case "IsDeleted":
|
case "IsDeleted":
|
||||||
user.IsDeleted = util.ParseBool(value)
|
user.IsDeleted = util.ParseBool(value)
|
||||||
case "CreatedIp":
|
case "CreatedIp":
|
||||||
user.CreatedIp = value
|
user.CreatedIp = value
|
||||||
|
case "PreferredMfaType":
|
||||||
|
user.PreferredMfaType = value
|
||||||
|
case "TotpSecret":
|
||||||
|
user.TotpSecret = value
|
||||||
|
case "SignupApplication":
|
||||||
|
user.SignupApplication = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) getUserValue(user *User, key string) string {
|
||||||
|
jsonData, _ := json.Marshal(user)
|
||||||
|
var mapData map[string]interface{}
|
||||||
|
if err := json.Unmarshal(jsonData, &mapData); err != nil {
|
||||||
|
fmt.Println("conversion failed:", err)
|
||||||
|
return user.Id
|
||||||
|
}
|
||||||
|
value := mapData[util.SnakeToCamel(key)]
|
||||||
|
|
||||||
|
if str, ok := value.(string); ok {
|
||||||
|
return str
|
||||||
|
} else {
|
||||||
|
if value != nil {
|
||||||
|
valType := reflect.TypeOf(value)
|
||||||
|
|
||||||
|
typeName := valType.Name()
|
||||||
|
switch typeName {
|
||||||
|
case "bool":
|
||||||
|
return strconv.FormatBool(value.(bool))
|
||||||
|
case "int":
|
||||||
|
return strconv.Itoa(value.(int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user.Id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,10 +293,12 @@ func (syncer *Syncer) getMapFromOriginalUser(user *OriginalUser) map[string]stri
|
|||||||
m["IsDefaultAvatar"] = util.BoolToString(user.IsDefaultAvatar)
|
m["IsDefaultAvatar"] = util.BoolToString(user.IsDefaultAvatar)
|
||||||
m["IsOnline"] = util.BoolToString(user.IsOnline)
|
m["IsOnline"] = util.BoolToString(user.IsOnline)
|
||||||
m["IsAdmin"] = util.BoolToString(user.IsAdmin)
|
m["IsAdmin"] = util.BoolToString(user.IsAdmin)
|
||||||
m["IsGlobalAdmin"] = util.BoolToString(user.IsGlobalAdmin)
|
|
||||||
m["IsForbidden"] = util.BoolToString(user.IsForbidden)
|
m["IsForbidden"] = util.BoolToString(user.IsForbidden)
|
||||||
m["IsDeleted"] = util.BoolToString(user.IsDeleted)
|
m["IsDeleted"] = util.BoolToString(user.IsDeleted)
|
||||||
m["CreatedIp"] = user.CreatedIp
|
m["CreatedIp"] = user.CreatedIp
|
||||||
|
m["PreferredMfaType"] = user.PreferredMfaType
|
||||||
|
m["TotpSecret"] = user.TotpSecret
|
||||||
|
m["SignupApplication"] = user.SignupApplication
|
||||||
|
|
||||||
m2 := map[string]string{}
|
m2 := map[string]string{}
|
||||||
for _, tableColumn := range syncer.TableColumns {
|
for _, tableColumn := range syncer.TableColumns {
|
||||||
@@ -288,19 +322,3 @@ func (syncer *Syncer) getSqlSetStringFromMap(m map[string]string) string {
|
|||||||
}
|
}
|
||||||
return strings.Join(tokens, ", ")
|
return strings.Join(tokens, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) getSqlKeyValueStringFromMap(m map[string]string) (string, string) {
|
|
||||||
typeMap := syncer.getTableColumnsTypeMap()
|
|
||||||
|
|
||||||
keys := []string{}
|
|
||||||
values := []string{}
|
|
||||||
for k, v := range m {
|
|
||||||
if typeMap[k] == "string" {
|
|
||||||
v = fmt.Sprintf("'%s'", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
keys = append(keys, k)
|
|
||||||
values = append(values, v)
|
|
||||||
}
|
|
||||||
return strings.Join(keys, ", "), strings.Join(values, ", ")
|
|
||||||
}
|
|
||||||
|
@@ -824,7 +824,6 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
|||||||
Type: "normal-user",
|
Type: "normal-user",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
IsDeleted: false,
|
IsDeleted: false,
|
||||||
Properties: map[string]string{
|
Properties: map[string]string{
|
||||||
|
@@ -123,7 +123,7 @@ var stToServiceResponse sync.Map
|
|||||||
// pgt is short for proxy granting ticket
|
// pgt is short for proxy granting ticket
|
||||||
var pgtToServiceResponse sync.Map
|
var pgtToServiceResponse sync.Map
|
||||||
|
|
||||||
func CheckCasRestrict(application *Application, lang string, service string) error {
|
func CheckCasLogin(application *Application, lang string, service string) error {
|
||||||
if len(application.RedirectUris) > 0 && !application.IsRedirectUriValid(service) {
|
if len(application.RedirectUris) > 0 && !application.IsRedirectUriValid(service) {
|
||||||
return fmt.Errorf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), service)
|
return fmt.Errorf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), service)
|
||||||
}
|
}
|
||||||
|
@@ -73,7 +73,6 @@ type UserWithoutThirdIdp struct {
|
|||||||
IsDefaultAvatar bool `json:"isDefaultAvatar"`
|
IsDefaultAvatar bool `json:"isDefaultAvatar"`
|
||||||
IsOnline bool `json:"isOnline"`
|
IsOnline bool `json:"isOnline"`
|
||||||
IsAdmin bool `json:"isAdmin"`
|
IsAdmin bool `json:"isAdmin"`
|
||||||
IsGlobalAdmin bool `json:"isGlobalAdmin"`
|
|
||||||
IsForbidden bool `json:"isForbidden"`
|
IsForbidden bool `json:"isForbidden"`
|
||||||
IsDeleted bool `json:"isDeleted"`
|
IsDeleted bool `json:"isDeleted"`
|
||||||
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
|
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
|
||||||
@@ -154,7 +153,6 @@ func getUserWithoutThirdIdp(user *User) *UserWithoutThirdIdp {
|
|||||||
IsDefaultAvatar: user.IsDefaultAvatar,
|
IsDefaultAvatar: user.IsDefaultAvatar,
|
||||||
IsOnline: user.IsOnline,
|
IsOnline: user.IsOnline,
|
||||||
IsAdmin: user.IsAdmin,
|
IsAdmin: user.IsAdmin,
|
||||||
IsGlobalAdmin: user.IsGlobalAdmin,
|
|
||||||
IsForbidden: user.IsForbidden,
|
IsForbidden: user.IsForbidden,
|
||||||
IsDeleted: user.IsDeleted,
|
IsDeleted: user.IsDeleted,
|
||||||
SignupApplication: user.SignupApplication,
|
SignupApplication: user.SignupApplication,
|
||||||
|
@@ -29,6 +29,19 @@ const (
|
|||||||
UserPropertiesWechatOpenId = "wechatOpenId"
|
UserPropertiesWechatOpenId = "wechatOpenId"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const UserEnforcerId = "built-in/user-enforcer-built-in"
|
||||||
|
|
||||||
|
var userEnforcer *UserGroupEnforcer
|
||||||
|
|
||||||
|
func InitUserManager() {
|
||||||
|
enforcer, err := GetInitializedEnforcer(UserEnforcerId)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userEnforcer = NewUserGroupEnforcer(enforcer.Enforcer)
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
@@ -70,7 +83,6 @@ type User struct {
|
|||||||
IsDefaultAvatar bool `json:"isDefaultAvatar"`
|
IsDefaultAvatar bool `json:"isDefaultAvatar"`
|
||||||
IsOnline bool `json:"isOnline"`
|
IsOnline bool `json:"isOnline"`
|
||||||
IsAdmin bool `json:"isAdmin"`
|
IsAdmin bool `json:"isAdmin"`
|
||||||
IsGlobalAdmin bool `json:"isGlobalAdmin"`
|
|
||||||
IsForbidden bool `json:"isForbidden"`
|
IsForbidden bool `json:"isForbidden"`
|
||||||
IsDeleted bool `json:"isDeleted"`
|
IsDeleted bool `json:"isDeleted"`
|
||||||
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
|
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
|
||||||
@@ -157,6 +169,7 @@ type User struct {
|
|||||||
Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
|
Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
|
||||||
Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
|
Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
|
||||||
MetaMask string `xorm:"metamask varchar(100)" json:"metamask"`
|
MetaMask string `xorm:"metamask varchar(100)" json:"metamask"`
|
||||||
|
Web3Onboard string `xorm:"web3onboard varchar(100)" json:"web3onboard"`
|
||||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||||
|
|
||||||
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
||||||
@@ -516,19 +529,26 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
|||||||
columns = []string{
|
columns = []string{
|
||||||
"owner", "display_name", "avatar",
|
"owner", "display_name", "avatar",
|
||||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||||
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
|
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
|
||||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||||
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
|
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
|
||||||
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
|
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
|
||||||
"spotify", "strava", "stripe", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
|
"spotify", "strava", "stripe", "type", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
|
||||||
"yammer", "yandex", "zoom", "custom",
|
"yammer", "yandex", "zoom", "custom",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isAdmin {
|
if isAdmin {
|
||||||
columns = append(columns, "name", "email", "phone", "country_code")
|
columns = append(columns, "name", "email", "phone", "country_code", "type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if util.ContainsString(columns, "groups") {
|
||||||
|
_, err := userEnforcer.UpdateGroupsForUser(user.GetId(), user.Groups)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := updateUser(id, user, columns)
|
affected, err := updateUser(id, user, columns)
|
||||||
@@ -607,12 +627,10 @@ func AddUser(user *User) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PasswordType == "" && organization.PasswordType != "" {
|
if user.PasswordType == "" || user.PasswordType == "plain" {
|
||||||
user.PasswordType = organization.PasswordType
|
user.UpdateUserPassword(organization)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.UpdateUserPassword(organization)
|
|
||||||
|
|
||||||
err = user.UpdateUserHash()
|
err = user.UpdateUserHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -778,6 +796,10 @@ func ExtendUserWithRolesAndPermissions(user *User) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteGroupForUser(user string, group string) (bool, error) {
|
||||||
|
return userEnforcer.DeleteGroupForUser(user, group)
|
||||||
|
}
|
||||||
|
|
||||||
func userChangeTrigger(oldName string, newName string) error {
|
func userChangeTrigger(oldName string, newName string) error {
|
||||||
session := ormer.Engine.NewSession()
|
session := ormer.Engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -866,5 +888,13 @@ func (user *User) IsApplicationAdmin(application *Application) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return (user.Owner == application.Organization && user.IsAdmin) || user.IsGlobalAdmin
|
return (user.Owner == application.Organization && user.IsAdmin) || user.IsGlobalAdmin()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) IsGlobalAdmin() bool {
|
||||||
|
if user == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.Owner == "built-in"
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -58,22 +59,15 @@ func downloadImage(client *http.Client, url string) (*bytes.Buffer, string, erro
|
|||||||
if strings.Contains(contentType, "text/html") {
|
if strings.Contains(contentType, "text/html") {
|
||||||
fileExtension = ".html"
|
fileExtension = ".html"
|
||||||
} else {
|
} else {
|
||||||
switch contentType {
|
fileExtensions, err := mime.ExtensionsByType(contentType)
|
||||||
case "image/jpeg":
|
if err != nil {
|
||||||
fileExtension = ".jpg"
|
return nil, "", err
|
||||||
case "image/png":
|
|
||||||
fileExtension = ".png"
|
|
||||||
case "image/gif":
|
|
||||||
fileExtension = ".gif"
|
|
||||||
case "image/vnd.microsoft.icon":
|
|
||||||
fileExtension = ".ico"
|
|
||||||
case "image/x-icon":
|
|
||||||
fileExtension = ".ico"
|
|
||||||
case "image/svg+xml":
|
|
||||||
fileExtension = ".svg"
|
|
||||||
default:
|
|
||||||
return nil, "", fmt.Errorf("unsupported content type: %s", contentType)
|
|
||||||
}
|
}
|
||||||
|
if fileExtensions == nil {
|
||||||
|
return nil, "", fmt.Errorf("fileExtensions is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileExtension = fileExtensions[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the image to a bytes.Buffer
|
// Save the image to a bytes.Buffer
|
||||||
|
143
object/user_enforcer.go
Normal file
143
object/user_enforcer.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/casbin/casbin/v2/errors"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserGroupEnforcer struct {
|
||||||
|
// use rbac model implement use group, the enforcer can also implement user role
|
||||||
|
enforcer *casbin.Enforcer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserGroupEnforcer(enforcer *casbin.Enforcer) *UserGroupEnforcer {
|
||||||
|
return &UserGroupEnforcer{
|
||||||
|
enforcer: enforcer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) checkModel() error {
|
||||||
|
if _, ok := e.enforcer.GetModel()["g"]; !ok {
|
||||||
|
return fmt.Errorf("The Casbin model used by enforcer doesn't support RBAC (\"[role_definition]\" section not found), please use a RBAC enabled Casbin model for the enforcer")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) AddGroupForUser(user string, group string) (bool, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.enforcer.AddRoleForUser(user, GetGroupWithPrefix(group))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) AddGroupsForUser(user string, groups []string) (bool, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := make([]string, len(groups))
|
||||||
|
for i, group := range groups {
|
||||||
|
g[i] = GetGroupWithPrefix(group)
|
||||||
|
}
|
||||||
|
return e.enforcer.AddRolesForUser(user, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) DeleteGroupForUser(user string, group string) (bool, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.enforcer.DeleteRoleForUser(user, GetGroupWithPrefix(group))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) DeleteGroupsForUser(user string) (bool, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.enforcer.DeleteRolesForUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetGroupsForUser(user string) ([]string, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
groups, err := e.enforcer.GetRolesForUser(user)
|
||||||
|
for i, group := range groups {
|
||||||
|
groups[i] = GetGroupWithoutPrefix(group)
|
||||||
|
}
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetAllUsersByGroup(group string) ([]string, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := e.enforcer.GetUsersForRole(GetGroupWithPrefix(group))
|
||||||
|
if err != nil {
|
||||||
|
if err == errors.ERR_NAME_NOT_FOUND {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupWithPrefix(group string) string {
|
||||||
|
return "group:" + group
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupWithoutPrefix(group string) string {
|
||||||
|
return group[len("group:"):]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) GetUserNamesByGroupName(groupName string) ([]string, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userIds, err := e.GetAllUsersByGroup(groupName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{}
|
||||||
|
for _, userId := range userIds {
|
||||||
|
_, name := util.GetOwnerAndNameFromIdNoCheck(userId)
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UserGroupEnforcer) UpdateGroupsForUser(user string, groups []string) (bool, error) {
|
||||||
|
err := e.checkModel()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = e.DeleteGroupsForUser(user)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := e.AddGroupsForUser(user, groups)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected, nil
|
||||||
|
}
|
@@ -73,8 +73,8 @@ func parseListItem(lines *[]string, i int) []string {
|
|||||||
return trimmedItems
|
return trimmedItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadUsers(owner string, fileId string) (bool, error) {
|
func UploadUsers(owner string, path string) (bool, error) {
|
||||||
table := xlsx.ReadXlsxFile(fileId)
|
table := xlsx.ReadXlsxFile(path)
|
||||||
|
|
||||||
oldUserMap, err := getUserMap(owner)
|
oldUserMap, err := getUserMap(owner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -124,15 +124,14 @@ func UploadUsers(owner string, fileId string) (bool, error) {
|
|||||||
IsDefaultAvatar: false,
|
IsDefaultAvatar: false,
|
||||||
IsOnline: parseLineItemBool(&line, 31),
|
IsOnline: parseLineItemBool(&line, 31),
|
||||||
IsAdmin: parseLineItemBool(&line, 32),
|
IsAdmin: parseLineItemBool(&line, 32),
|
||||||
IsGlobalAdmin: parseLineItemBool(&line, 33),
|
IsForbidden: parseLineItemBool(&line, 33),
|
||||||
IsForbidden: parseLineItemBool(&line, 34),
|
IsDeleted: parseLineItemBool(&line, 34),
|
||||||
IsDeleted: parseLineItemBool(&line, 35),
|
SignupApplication: parseLineItem(&line, 35),
|
||||||
SignupApplication: parseLineItem(&line, 36),
|
|
||||||
Hash: "",
|
Hash: "",
|
||||||
PreHash: "",
|
PreHash: "",
|
||||||
CreatedIp: parseLineItem(&line, 37),
|
CreatedIp: parseLineItem(&line, 36),
|
||||||
LastSigninTime: parseLineItem(&line, 38),
|
LastSigninTime: parseLineItem(&line, 37),
|
||||||
LastSigninIp: parseLineItem(&line, 39),
|
LastSigninIp: parseLineItem(&line, 38),
|
||||||
Ldap: "",
|
Ldap: "",
|
||||||
Properties: map[string]string{},
|
Properties: map[string]string{},
|
||||||
}
|
}
|
||||||
|
@@ -310,10 +310,7 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
|
|||||||
item := GetAccountItemByName("Is admin", organization)
|
item := GetAccountItemByName("Is admin", organization)
|
||||||
itemsChanged = append(itemsChanged, item)
|
itemsChanged = append(itemsChanged, item)
|
||||||
}
|
}
|
||||||
if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
|
|
||||||
item := GetAccountItemByName("Is global admin", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.IsForbidden != newUser.IsForbidden {
|
if oldUser.IsForbidden != newUser.IsForbidden {
|
||||||
item := GetAccountItemByName("Is forbidden", organization)
|
item := GetAccountItemByName("Is forbidden", organization)
|
||||||
itemsChanged = append(itemsChanged, item)
|
itemsChanged = append(itemsChanged, item)
|
||||||
@@ -351,5 +348,5 @@ func (user *User) IsAdminUser() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.IsAdmin || user.IsGlobalAdmin
|
return user.IsAdmin || user.IsGlobalAdmin()
|
||||||
}
|
}
|
||||||
|
@@ -19,12 +19,22 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sendWebhook(webhook *Webhook, record *Record) error {
|
func sendWebhook(webhook *Webhook, record *casvisorsdk.Record, extendedUser *User) error {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
body := strings.NewReader(util.StructToJson(record))
|
type RecordEx struct {
|
||||||
|
casvisorsdk.Record
|
||||||
|
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
||||||
|
}
|
||||||
|
recordEx := &RecordEx{
|
||||||
|
Record: *record,
|
||||||
|
ExtendedUser: extendedUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
body := strings.NewReader(util.StructToJson(recordEx))
|
||||||
|
|
||||||
req, err := http.NewRequest(webhook.Method, webhook.Url, body)
|
req, err := http.NewRequest(webhook.Method, webhook.Url, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -90,7 +90,7 @@ func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
ProductName: productName,
|
ProductName: productName,
|
||||||
ProductDisplayName: productDisplayName,
|
ProductDisplayName: productDisplayName,
|
||||||
ProviderName: providerName,
|
ProviderName: providerName,
|
||||||
OutOrderId: orderId,
|
OrderId: orderId,
|
||||||
PaymentStatus: PaymentStatePaid,
|
PaymentStatus: PaymentStatePaid,
|
||||||
Price: price,
|
Price: price,
|
||||||
PaymentName: paymentName,
|
PaymentName: paymentName,
|
||||||
|
@@ -14,10 +14,7 @@
|
|||||||
|
|
||||||
package pp
|
package pp
|
||||||
|
|
||||||
import (
|
import "net/http"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DummyPaymentProvider struct{}
|
type DummyPaymentProvider struct{}
|
||||||
|
|
||||||
@@ -27,8 +24,7 @@ func NewDummyPaymentProvider() (*DummyPaymentProvider, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pp *DummyPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
|
func (pp *DummyPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
|
||||||
payUrl := fmt.Sprintf("/payments/%s/result", paymentName)
|
return returnUrl, "", nil
|
||||||
return payUrl, "", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
|
2
pp/gc.go
2
pp/gc.go
@@ -255,7 +255,7 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
|
|||||||
ProductName: productName,
|
ProductName: productName,
|
||||||
ProductDisplayName: productDisplayName,
|
ProductDisplayName: productDisplayName,
|
||||||
ProviderName: providerName,
|
ProviderName: providerName,
|
||||||
OutOrderId: orderId,
|
OrderId: orderId,
|
||||||
Price: price,
|
Price: price,
|
||||||
PaymentStatus: PaymentStatePaid,
|
PaymentStatus: PaymentStatePaid,
|
||||||
PaymentName: paymentName,
|
PaymentName: paymentName,
|
||||||
|
16
pp/paypal.go
16
pp/paypal.go
@@ -52,13 +52,12 @@ func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentPro
|
|||||||
|
|
||||||
func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
|
func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
|
||||||
// https://github.com/go-pay/gopay/blob/main/doc/paypal.md
|
// https://github.com/go-pay/gopay/blob/main/doc/paypal.md
|
||||||
priceStr := strconv.FormatFloat(price, 'f', 2, 64)
|
|
||||||
units := make([]*paypal.PurchaseUnit, 0, 1)
|
units := make([]*paypal.PurchaseUnit, 0, 1)
|
||||||
unit := &paypal.PurchaseUnit{
|
unit := &paypal.PurchaseUnit{
|
||||||
ReferenceId: util.GetRandomString(16),
|
ReferenceId: util.GetRandomString(16),
|
||||||
Amount: &paypal.Amount{
|
Amount: &paypal.Amount{
|
||||||
CurrencyCode: currency, // e.g."USD"
|
CurrencyCode: currency, // e.g."USD"
|
||||||
Value: priceStr, // e.g."100.00"
|
Value: priceFloat64ToString(price), // e.g."100.00"
|
||||||
},
|
},
|
||||||
Description: joinAttachString([]string{productDisplayName, productName, providerName}),
|
Description: joinAttachString([]string{productDisplayName, productName, providerName}),
|
||||||
}
|
}
|
||||||
@@ -115,8 +114,8 @@ func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if captureRsp.Code != paypal.Success {
|
if detailRsp.Code != paypal.Success {
|
||||||
errDetail := captureRsp.ErrorResponse.Details[0]
|
errDetail := detailRsp.ErrorResponse.Details[0]
|
||||||
switch errDetail.Issue {
|
switch errDetail.Issue {
|
||||||
case "ORDER_NOT_APPROVED":
|
case "ORDER_NOT_APPROVED":
|
||||||
notifyResult.PaymentStatus = PaymentStateCanceled
|
notifyResult.PaymentStatus = PaymentStateCanceled
|
||||||
@@ -147,16 +146,15 @@ func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
paymentStatus = PaymentStateError
|
paymentStatus = PaymentStateError
|
||||||
}
|
}
|
||||||
notifyResult = &NotifyResult{
|
notifyResult = &NotifyResult{
|
||||||
PaymentStatus: paymentStatus,
|
PaymentStatus: paymentStatus,
|
||||||
PaymentName: paymentName,
|
PaymentName: paymentName,
|
||||||
|
|
||||||
ProductName: productName,
|
ProductName: productName,
|
||||||
ProductDisplayName: productDisplayName,
|
ProductDisplayName: productDisplayName,
|
||||||
ProviderName: providerName,
|
ProviderName: providerName,
|
||||||
Price: price,
|
Price: price,
|
||||||
Currency: currency,
|
Currency: currency,
|
||||||
|
|
||||||
OutOrderId: orderId,
|
OrderId: orderId,
|
||||||
}
|
}
|
||||||
return notifyResult, nil
|
return notifyResult, nil
|
||||||
}
|
}
|
||||||
|
@@ -14,9 +14,7 @@
|
|||||||
|
|
||||||
package pp
|
package pp
|
||||||
|
|
||||||
import (
|
import "net/http"
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentState string
|
type PaymentState string
|
||||||
|
|
||||||
@@ -24,6 +22,7 @@ const (
|
|||||||
PaymentStatePaid PaymentState = "Paid"
|
PaymentStatePaid PaymentState = "Paid"
|
||||||
PaymentStateCreated PaymentState = "Created"
|
PaymentStateCreated PaymentState = "Created"
|
||||||
PaymentStateCanceled PaymentState = "Canceled"
|
PaymentStateCanceled PaymentState = "Canceled"
|
||||||
|
PaymentStateTimeout PaymentState = "Timeout"
|
||||||
PaymentStateError PaymentState = "Error"
|
PaymentStateError PaymentState = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,13 +31,13 @@ type NotifyResult struct {
|
|||||||
PaymentStatus PaymentState
|
PaymentStatus PaymentState
|
||||||
NotifyMessage string
|
NotifyMessage string
|
||||||
|
|
||||||
ProviderName string
|
|
||||||
ProductName string
|
ProductName string
|
||||||
ProductDisplayName string
|
ProductDisplayName string
|
||||||
|
ProviderName string
|
||||||
Price float64
|
Price float64
|
||||||
Currency string
|
Currency string
|
||||||
|
|
||||||
OutOrderId string
|
OrderId string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentProvider interface {
|
type PaymentProvider interface {
|
||||||
@@ -75,6 +74,12 @@ func GetPaymentProvider(typ string, clientId string, clientSecret string, host s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pp, nil
|
return pp, nil
|
||||||
|
} else if typ == "Stripe" {
|
||||||
|
pp, err := NewStripePaymentProvider(clientId, clientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
166
pp/stripe.go
Normal file
166
pp/stripe.go
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
// 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 pp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
"github.com/stripe/stripe-go/v74"
|
||||||
|
stripeCheckout "github.com/stripe/stripe-go/v74/checkout/session"
|
||||||
|
stripeIntent "github.com/stripe/stripe-go/v74/paymentintent"
|
||||||
|
stripePrice "github.com/stripe/stripe-go/v74/price"
|
||||||
|
stripeProduct "github.com/stripe/stripe-go/v74/product"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StripePaymentProvider struct {
|
||||||
|
PublishableKey string
|
||||||
|
SecretKey string
|
||||||
|
isProd bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStripePaymentProvider(PublishableKey, SecretKey string) (*StripePaymentProvider, error) {
|
||||||
|
isProd := false
|
||||||
|
if conf.GetConfigString("runmode") == "prod" {
|
||||||
|
isProd = true
|
||||||
|
}
|
||||||
|
pp := &StripePaymentProvider{
|
||||||
|
PublishableKey: PublishableKey,
|
||||||
|
SecretKey: SecretKey,
|
||||||
|
isProd: isProd,
|
||||||
|
}
|
||||||
|
stripe.Key = pp.SecretKey
|
||||||
|
return pp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *StripePaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (payUrl string, orderId string, err error) {
|
||||||
|
// Create a temp product
|
||||||
|
description := joinAttachString([]string{productName, productDisplayName, providerName})
|
||||||
|
productParams := &stripe.ProductParams{
|
||||||
|
Name: stripe.String(productDisplayName),
|
||||||
|
Description: stripe.String(description),
|
||||||
|
DefaultPriceData: &stripe.ProductDefaultPriceDataParams{
|
||||||
|
UnitAmount: stripe.Int64(priceFloat64ToInt64(price)),
|
||||||
|
Currency: stripe.String(currency),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sProduct, err := stripeProduct.New(productParams)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
// Create a price for an existing product
|
||||||
|
priceParams := &stripe.PriceParams{
|
||||||
|
Currency: stripe.String(currency),
|
||||||
|
UnitAmount: stripe.Int64(priceFloat64ToInt64(price)),
|
||||||
|
Product: stripe.String(sProduct.ID),
|
||||||
|
}
|
||||||
|
sPrice, err := stripePrice.New(priceParams)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
// Create a Checkout Session
|
||||||
|
checkoutParams := &stripe.CheckoutSessionParams{
|
||||||
|
LineItems: []*stripe.CheckoutSessionLineItemParams{
|
||||||
|
{
|
||||||
|
Price: stripe.String(sPrice.ID),
|
||||||
|
Quantity: stripe.Int64(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),
|
||||||
|
SuccessURL: stripe.String(returnUrl),
|
||||||
|
CancelURL: stripe.String(returnUrl),
|
||||||
|
ClientReferenceID: stripe.String(paymentName),
|
||||||
|
ExpiresAt: stripe.Int64(time.Now().Add(30 * time.Minute).Unix()),
|
||||||
|
}
|
||||||
|
checkoutParams.AddMetadata("product_description", description)
|
||||||
|
sCheckout, err := stripeCheckout.New(checkoutParams)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return sCheckout.URL, sCheckout.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *StripePaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
|
notifyResult := &NotifyResult{}
|
||||||
|
sCheckout, err := stripeCheckout.Get(orderId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch sCheckout.Status {
|
||||||
|
case "open":
|
||||||
|
// The checkout session is still in progress. Payment processing has not started
|
||||||
|
notifyResult.PaymentStatus = PaymentStateCreated
|
||||||
|
return notifyResult, nil
|
||||||
|
case "complete":
|
||||||
|
// The checkout session is complete. Payment processing may still be in progress
|
||||||
|
case "expired":
|
||||||
|
// The checkout session has expired. No further processing will occur
|
||||||
|
notifyResult.PaymentStatus = PaymentStateTimeout
|
||||||
|
return notifyResult, nil
|
||||||
|
default:
|
||||||
|
notifyResult.PaymentStatus = PaymentStateError
|
||||||
|
notifyResult.NotifyMessage = fmt.Sprintf("unexpected stripe checkout status: %v", sCheckout.Status)
|
||||||
|
return notifyResult, nil
|
||||||
|
}
|
||||||
|
switch sCheckout.PaymentStatus {
|
||||||
|
case "paid":
|
||||||
|
// Skip
|
||||||
|
case "unpaid":
|
||||||
|
notifyResult.PaymentStatus = PaymentStateCreated
|
||||||
|
return notifyResult, nil
|
||||||
|
default:
|
||||||
|
notifyResult.PaymentStatus = PaymentStateError
|
||||||
|
notifyResult.NotifyMessage = fmt.Sprintf("unexpected stripe checkout payment status: %v", sCheckout.PaymentStatus)
|
||||||
|
return notifyResult, nil
|
||||||
|
}
|
||||||
|
// Once payment is successful, the Checkout Session will contain a reference to the successful `PaymentIntent`
|
||||||
|
sIntent, err := stripeIntent.Get(sCheckout.PaymentIntent.ID, nil)
|
||||||
|
var (
|
||||||
|
productName string
|
||||||
|
productDisplayName string
|
||||||
|
providerName string
|
||||||
|
)
|
||||||
|
if description, ok := sCheckout.Metadata["product_description"]; ok {
|
||||||
|
productName, productDisplayName, providerName, _ = parseAttachString(description)
|
||||||
|
}
|
||||||
|
notifyResult = &NotifyResult{
|
||||||
|
PaymentName: sCheckout.ClientReferenceID,
|
||||||
|
PaymentStatus: PaymentStatePaid,
|
||||||
|
|
||||||
|
ProductName: productName,
|
||||||
|
ProductDisplayName: productDisplayName,
|
||||||
|
ProviderName: providerName,
|
||||||
|
|
||||||
|
Price: priceInt64ToFloat64(sIntent.Amount),
|
||||||
|
Currency: string(sIntent.Currency),
|
||||||
|
|
||||||
|
OrderId: orderId,
|
||||||
|
}
|
||||||
|
return notifyResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *StripePaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *StripePaymentProvider) GetResponseError(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return "success"
|
||||||
|
} else {
|
||||||
|
return "fail"
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user